五大經典算法總結

       馬上要開始投簡歷找實習了,自己還是毛都不會,慌得一筆,從今天開始每天刷2道以上的leetcode然後總結,並且總結各種面試題的知識點,以後常複習,加油。

        在刷leetcode時經常看到有人說DP,然後去百度了DP是個啥,才知道DP是五大經典算法之一,今天開始總結一下五大經典算法。

        五大經典算法分爲

1、分治法:把一個複雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。

2、動態規劃法:每次決策依賴於當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱爲動態規劃。

3、貪心算法:在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的僅是在某種意義上的局部最優解。 常見的貪心算法有:Prim算法、Kruskal算法(都是求最小生成樹的)。

基本思路:將問題分解爲若干個小問題,逐漸求得各個子問題的局部最優解,最後合併爲原來問題的解。

4、回溯法:回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。深度優先;

       回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。

5、分支限界法:類似於回溯法,也是一種在問題的解空間樹T上搜索問題解的算法。但在一般情況下,分支限界法與回溯法的求解目標不同。回溯法的求解目標是找出T中滿足約束條件的所有解,而分支限界法的求解目標則是找出滿足約束條件的一個解,或是在滿足約束條件的解中找出使某一目標函數值達到極大或極小的解,即在某種意義下的最優解。

一、分治法

分治法所能解決的問題一般具有以下幾個特徵:
    1) 該問題的規模縮小到一定的程度就可以容易地解決
    2) 該問題可以分解爲若干個規模較小的相同問題,即該問題具有最優子結構性質。
    3) 利用該問題分解出的子問題的解可以合併爲該問題的解;

    4) 該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子子問題。

若不具備第三條特徵,可考慮採用動態規劃法(DP)或者貪心法。

若不具備第四條特徵,可考慮採用動態規劃法。

分治法基本步驟:

    step1 分解:將原問題分解爲若干個規模較小,相互獨立,與原問題形式相同的子問題;
    step2 解決:若子問題規模較小而容易被解決則直接解,否則遞歸地解各個子問題

    step3 合併:將各個子問題的解合併爲原問題的解。

可使用分治法求解的一些經典問題:

(1)二分搜索
(2)大整數乘法
(3)Strassen矩陣乘法
(4)棋盤覆蓋
(5)合併排序
(6)快速排序
(7)線性時間選擇
(8)最接近點對問題
(9)循環賽日程表

(10)漢諾塔

二、動態規劃法

 與分治法最大的差別是:適合於用動態規劃法求解的問題,經分解後得到的子問題往往不是互相獨立的(即下一個子階段的求解是建立在上一個子階段的解的基礎上,進行進一步的求解)。

適用條件:

能採用動態規劃求解的問題的一般要具有3個性質:
    (1) 最優化原理:如果問題的最優解所包含的子問題的解也是最優的,就稱該問題具有最優子結構,即滿足最優化原理。
    (2) 無後效性:即某階段狀態一旦確定,就不受這個狀態以後決策的影響。也就是說,某狀態以後的過程不會影響以前的狀態,只與當前狀態有關。

   (3)有重疊子問題:即子問題之間是不獨立的,一個子問題在下一階段決策中可能被多次使用到。(該性質並不是動態規劃適用的必要條件,但是如果沒有這條性質,動態規劃算法同其他算法相比就不具備優勢)

案例:

有n級臺階,一個人每次上一級或者兩級,問有多少種走完n級臺階的方法。
分析:動態規劃的實現的關鍵在於能不能準確合理的用動態規劃表來抽象出 實際問題。在這個問題上,我們讓f(n)表示走上n級臺階的方法數。

那麼當n爲1時,f(n) = 1,n爲2時,f(n) =2,就是說當臺階只有一級的時候,方法數是一種,臺階有兩級的時候,方法數爲2。那麼當我們要走上n級臺階,必然是從n-1級臺階邁一步或者是從n-2級臺階邁兩步,所以到達n級臺階的方法數必然是到達n-1級臺階的方法數加上到達n-2級臺階的方法數之和。即f(n) = f(n-1)+f(n-2),我們用dp[n]來表示動態規劃表,dp[i],i>0,i<=n,表示到達i級臺階的方法數。

int fun(int n){  
    if (n==1||n==2)  
        return n;  
    /*判斷n-1的狀態有沒有被計算過*/  
    if (!dp[n-1])  
        dp[n-1] = fun(n-1);  
    if(!dp[n-2])  
        dp[n-2]=fun(n-2);  
    return dp[n-1]+dp[n-2];  
}  

三、貪心算法

貪心算法是指在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,只做出在某種意義上的局部最優解。貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。
解題的一般步驟是:
1.建立數學模型來描述問題;
2.把求解的問題分成若干個子問題;
3.對每一子問題求解,得到子問題的局部最優解;

4.把子問題的局部最優解合成原來問題的一個解。

例子:錢幣找零問題

這個問題在我們的日常生活中就更加普遍了。假設1元、2元、5元、10元、20元、50元、100元的紙幣分別有c0, c1, c2, c3, c4, c5, c6張。現在要用這些錢來支付K元,至少要用多少張紙幣?用貪心算法的思想,很顯然,每一步儘可能用面值大的紙幣即可。在日常生活中我們自然而然也是這麼做的。在程序中已經事先將Value按照從小到大的順序排好。

public class charge {
    public static void main(String[] args) {
        // TODO 自動生成的方法存根
    	int res = charge(84);
    	System.out.println(res);
    }
 
   private static int charge(int money) {
	   int count = 0;
       int value[] = {50,20,10,5,2,1};
       while(money>0){
       	int length = value.length;
       	for(int i=0;i<length;i++){
       		while(money>=value[i]){
       			money=money-value[i];
       			count++;
       			//System.out.println(money);
       		}
       	}
       }
       return count;
	}     
}

 四、回溯法

        回溯法是一種系統地搜索問題解答的方法。在搜索的過程中嘗試找到問題的解,如果發現找不到了,就退一步,往上回溯(剪枝過程)。對於許多複雜問題和大規模問題都可以使用回溯法。 
      回溯法的基本思想是按照深度優先搜索的策略,從根節點開始搜索,當到某個節點時要判斷是否是包含問題的解,如果包含就從該節點繼續搜索下去,如果不包含,就向父節點回溯。若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。而若使用回溯法求任一個解時,只要搜索到問題的一個解就可以結束。 

      回溯法常用的剪枝函數:(1)約束函數:在節點處減去不滿足約束的子樹。(2)界限函數:減去得不到最優解的子樹。

一般步驟:

1、針對所給問題,確定問題的解空間
2、利用適於搜索的方法組織解空間
3、利用深度優先搜索解空間

4、在搜索過程中用剪枝函數避免無效搜索。

舉例:N皇后問題

在一個N*N的棋盤上放置N個皇后,每行一個並使其不能互相攻擊(同一行、同一列、同一斜線上的皇后都會自動攻擊)。

暫缺代碼


五、

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章