1. 澶у﹀叚縐嶇▼搴忓憳瀹炵敤綆楁硶鎺ㄨ崘
紼嬪簭鍛樺疄鐢ㄧ畻娉曟湁鐢ㄦ帹鑽
綆楁硶涓: 蹇閫熸帓搴忕畻娉
蹇閫熸帓搴忔槸鐢變笢灝悸烽湇灝旀墍鍙戝睍鐨勪竴縐嶆帓搴忕畻娉曘傚湪騫沖潎鐘跺喌涓嬶紝鎺掑簭 n 涓欏圭洰瑕丱(nlog n)嬈℃瘮杈冦傚湪鏈鍧忕姸鍐典笅鍒欓渶瑕丱(n2)嬈℃瘮杈冿紝浣嗚繖縐嶇姸鍐靛苟涓嶅父瑙併備簨瀹炰笂錛屽揩閫熸帓搴忛氬父鏄庢樉姣斿叾浠朞(n log n) 綆楁硶鏇村揩錛屽洜涓哄畠鐨勫唴閮ㄥ驚鐜 (inner loop)鍙浠ュ湪澶ч儴鍒嗙殑鏋舵瀯涓婂緢鏈夋晥鐜囧湴琚瀹炵幇鍑烘潵銆
蹇閫熸帓搴忎嬌鐢ㄥ垎娌繪硶絳栫暐鏉ユ妸涓涓涓茶(list)鍒嗕負涓や釜瀛愪覆琛(sub-lists)銆
綆楁硶浜: 鍫嗘帓搴忕畻娉
鍫嗘帓搴(Heapsort)鏄鎸囧埄鐢ㄥ爢榪欑嶆暟鎹緇撴瀯鎵璁捐$殑涓縐嶆帓搴忕畻娉曘傚爢縐鏄涓涓榪戜技瀹屽叏浜屽弶鏍戠殑緇撴瀯錛屽苟鍚屾椂婊¤凍鍫嗙Н鐨勬ц川:鍗沖瓙緇撶偣鐨勯敭鍊兼垨緔㈠紩鎬繪槸灝忎簬(鎴栬呭ぇ浜)瀹冪殑鐖惰妭鐐廣
鍫嗘帓搴忕殑騫沖潎鏃墮棿澶嶆潅搴︿負O(nlogn)
綆楁硶涓: 褰掑苟鎺掑簭
褰掑苟鎺掑簭(Merge sort錛屽彴婀捐瘧浣:鍚堝苟鎺掑簭)鏄寤虹珛鍦ㄥ綊婢′綔涓婄殑涓縐嶆湁鏁堢殑鎺掑簭綆楁硶銆傝ョ畻娉曟槸閲囩敤鍒嗘不娉(Divide andConquer)鐨勪竴涓闈炲父鍏稿瀷鐨勫簲鐢ㄣ
綆楁硶鍥:浜屽垎鏌ユ壘綆楁硶
浜屽垎鏌ユ壘綆楁硶鏄涓縐嶅湪鏈夊簭鏁扮粍涓鏌ユ壘鏌愪竴鐗瑰畾鍏冪礌鐨勬悳緔㈢畻娉曘傛悳緔犺繃紼嬩粠鏁扮粍鐨勪腑闂村厓緔犲紑濮嬶紝濡傛灉涓闂村厓緔犳eソ鏄瑕佹煡鎵劇殑鍏冪礌錛屽垯鎼滅礌榪囩▼緇撴潫:濡傛灉鏌愪竴鐗 瀹氬厓緔犲ぇ騫叉垨鑰呭皬騫蹭腑闂村厓緔狅紝鍒欏湪鏁扮粍澶т簬鎴栧皬騫蹭腑闂村厓緔犵殑閭d竴鍗婁腑鏌ユ壘錛岃屼笖璺熷紑濮嬩竴鏍蜂粠涓闂村厓緔犲紑濮嬫瘮杈冦傚傛灉鍦ㄦ煇涓姝ラゆ暟緇勪負絀猴紝鍒欎唬琛ㄦ壘涓嶅埌銆傝繖 縐嶆悳緔㈢畻娉曟瘡涓嬈℃瘮杈冮兘浣挎悳緔㈣寖鍥寸緝灝忎竴鍗娿傛姌鍗婃悳緔㈡瘡嬈℃妸鎼滅儲鍖哄煙鍑忓皯涓鍗婏紝鏃墮棿澶嶆潅搴︿負O(logn) 銆
綆楁硶浜: BFPRT(綰挎ф煡鎵劇畻娉)
BFPRT綆楁硶瑙e喅鐨勯棶棰樺嶮鍒嗙粡鍏革紝鍗充粠鏌恘涓鍏冪礌鐨勫簭鍒椾腑閫夊嚭絎琸澶(絎琸灝)鐨勫厓緔狅紝閫氳繃宸у欑殑鍒嗘瀽錛孊FPRT鍙浠ヤ繚璇佸湪鏈鍧忔儏鍐典笅浠嶄負綰挎ф椂闂村嶆潅搴︺傝ョ畻 娉曠殑鎬濇兂涓庡揩閫熸帓搴忔濇兂鐩鎬技錛屽綋鐒訛紝涓轟嬌寰楃畻娉曞湪鏈鍧忔儏鍐典笅錛屼緷鐒惰兘杈懼埌o(n)鐨勬椂闂村嶆潅搴︼紝浜斾綅綆楁硶浣滆呭仛浜嗙簿濡欑殑澶勭悊銆
綆楁硶鍏: BFS(騫垮害浼樺厛鎼滅儲)
騫垮害浼樺厛鎼滅儲綆楁硶(Breadth-First-Search)錛屾槸涓縐嶅浘褰㈡悳緔㈢畻娉曘傜畝鍗曠殑璇碆FS鏄浠庢牴鑺傜偣寮濮嬶紝媧葷潃鏍(鍥)鐨勫藉害閬嶅巻鏍(鍥)鐨勮妭鐐廣傚傛灉鎵鏈夎妭鐐瑰潎琚璁塊棶錛屽垯綆楁硶涓姝銆侭FS鍚屾牱灞炰簬鐩茬洰鎼滅儲銆備竴鑸鐢ㄩ槦鍒楁暟鎹緇撴瀯鏉ヨ緟鍔╁疄鐜癇FS綆楁硶銆
對於一名優秀的程序員來說,面對一個項目的需求的時候,一定會在腦海里浮現出最適合解決這個問題的方法是什麼,選對了演算法,就會起到事半功倍的效果,反之,則可能會使程序運行效率低下,還容易出bug。因此,熟悉掌握常用的演算法,是對於一個優秀程序員最基本的要求。
那麼,常用的演算法都有哪些呢?一般來講,在我們日常工作中涉及到的演算法,通常分為以下幾個類型:分治、貪心、迭代、枚舉、回溯、動態規劃。下面我們來一一介紹這幾種演算法。
一、分治演算法
分治演算法,顧名思義,是將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
分治演算法一般分為三個部分:分解問題、解決問題、合並解。
分治演算法適用於那些問題的規模縮小到一定程度就可以解決、並且各子問題之間相互獨立,求出來的解可以合並為該問題的解的情況。
典型例子比如求解一個無序數組中的最大值,即可以採用分治演算法,示例如下:
def pidAndConquer(arr,leftIndex,rightIndex):
if(rightIndex==leftIndex+1 || rightIndex==leftIndex){
return Math.max(arr[leftIndex],arr[rightIndex]);
}
int mid=(leftIndex+rightIndex)/2;
int leftMax=pidAndConquer(arr,leftIndex,mid);
int rightMax=pidAndConquer(arr,mid,rightIndex);
return Math.max(leftMax,rightMax);
二、貪心演算法
貪心演算法是指在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的僅是在某種意義上的局部最優解。
貪心演算法的基本思路是把問題分成若干個子問題,然後對每個子問題求解,得到子問題的局部最優解,最後再把子問題的最優解合並成原問題的一個解。這里要注意一點就是貪心演算法得到的不一定是全局最優解。這一缺陷導致了貪心演算法的適用范圍較少,更大的用途在於平衡演算法效率和最終結果應用,類似於:反正就走這么多步,肯定給你一個值,至於是不是最優的,那我就管不了了。就好像去菜市場買幾樣菜,可以經過反復比價之後再買,或者是看到有賣的不管三七二十一先買了,總之最終結果是菜能買回來,但搞不好多花了幾塊錢。
典型例子比如部分背包問題:有n個物體,第i個物體的重量為Wi,價值為Vi,在總重量不超過C的情況下讓總價值盡量高。每一個物體可以只取走一部分,價值和重量按比例計算。
貪心策略就是,每次都先拿性價比高的,判斷不超過C。
三、迭代演算法
迭代法也稱輾轉法,是一種不斷用變數的舊值遞推新值的過程。迭代演算法是用計算機解決問題的一種基本方法,它利用計算機運算速度快、適合做重復性操作的特點,讓計算機對一組指令(或一定步驟)進行重復執行,在每次執行這組指令(或這些步驟)時,都從變數的原值推出它的一個新值。最終得到問題的結果。
迭代演算法適用於那些每步輸入參數變數一定,前值可以作為下一步輸入參數的問題。
典型例子比如說,用迭代演算法計算斐波那契數列。
四、枚舉演算法
枚舉演算法是我們在日常中使用到的最多的一個演算法,它的核心思想就是:枚舉所有的可能。枚舉法的本質就是從所有候選答案中去搜索正確地解。
枚舉演算法適用於候選答案數量一定的情況。
典型例子包括雞錢問題,有公雞5,母雞3,三小雞1,求m錢n雞的所有可能解。可以採用一個三重循環將所有情況枚舉出來。代碼如下:
五、回溯演算法
回溯演算法是一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就「回溯」返回,嘗試別的路徑。
許多復雜的,規模較大的問題都可以使用回溯法,有「通用解題方法」的美稱。
典型例子是8皇後演算法。在8 8格的國際象棋上擺放八個皇後,使其不能互相攻擊,即任意兩個皇後都不能處於同一行、同一列或同一斜線上,問一共有多少種擺法。
回溯法是求解皇後問題最經典的方法。演算法的思想在於如果一個皇後選定了位置,那麼下一個皇後的位置便被限制住了,下一個皇後需要一直找直到找到安全位置,如果沒有找到,那麼便要回溯到上一個皇後,那麼上一個皇後的位置就要改變,這樣一直遞歸直到所有的情況都被舉出。
六、動態規劃演算法
動態規劃過程是:每次決策依賴於當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱為動態規劃。
動態規劃演算法適用於當某階段狀態給定以後,在這階段以後的過程的發展不受這段以前各段狀態的影響,即無後效性的問題。
典型例子比如說背包問題,給定背包容量及物品重量和價值,要求背包裝的物品價值最大。