java——遞迴(動態規劃,回溯)

來源:互聯網
上載者:User

標籤:遞迴   generate   實現   常用   logs   排序演算法   劍指offer   sar   blog   

最近刷面試題經常刷到遞迴方面的演算法,一直以為都是遞迴,後來發現竟然都有具體的叫法,所以寫了這篇部落格來牢記以下

1. 五大常用演算法

(1) 分治演算法

把一個複雜的問題分成兩個或多個相同或者相似的子問題,然後不斷地細分,直到最後的子問題可以很簡單地求解出來,原問題的解就是自問題的合并。比如常見的快速排序演算法和歸併演算法

分治法的核心思想就是把大的難解的問題不斷分割,分而治之。

(2) 動態規劃

類似於分治法,將帶求解的問題分化成幾個小問題,每個小問題的解會影響原問題的解。

先求每個子問題的局部解,然後通過決策保留那些可能達到最優解的局部解

能夠分解成若干子問題,且子問題之間有交叉

(3) 回溯演算法

類似於一個枚舉的過程,其實也是一個建樹的過程,是樹的深度優先搜尋。

在搜尋嘗試過程中,發現當前節點已經不能滿足求解條件時,就返回其父節點,繼續嘗試別的路徑

(4) 分支界限法

類似於回溯演算法,不過不是深度優先搜尋,而是廣度優先搜尋,一般是用到queue(先進先出)來對每一個節點進行判斷。

(5) 貪心演算法

在問題求解時,總是找到局部最優解,而不是整體上最優。

貪心演算法的前提:局部最優策略能最終產生全域的最優解

 

2. 遞迴(個人感覺這個學會了,演算法只是如何調用遞迴)

先上一個最簡單的遞迴代碼,斐波那契數列

public class Fibo {    public int[] array = new int[100];{        array[0]=0;        array[1]=1;        array[2]=1;}        public int Fibonacci(int n){        if(n==1||n==2){            return 1;        }else{            return this.array[n]=Fibonacci(n-1)+Fibonacci(n-2);        }            }    public static void main(String[] args) {        // TODO Auto-generated method stub        Fibo fb = new Fibo();        System.out.println(fb.Fibonacci(3));    }}

當然,也可以來個偽遞迴,就是建立一個數組,把答案先預存起來,然後直接返回結果。劍指offer上很多直接遞迴是通不過的,必須要偽遞迴才可以

再來個青蛙跳台階的代碼,題目同樣是劍指offer上的

//一隻青蛙一次可以跳上1級台階,也可以跳上2級。//求該青蛙跳上一個n級的台階總共有多少種跳法public class JumpFloor {        public int Jump(int target){        if(target==0){            return 0;        }else if(target==1){            return 1;        }else if(target==2){            return 2;        }else{            int[] array = new int[target+1];            array[0]=0;            array[1]=1;            array[2]=2;            for(int i=3;i<array.length;i++){                array[i]=array[i-1]+array[i-2];            }            return array[target];        }            }        //一隻青蛙一次可以跳上1級台階,也可以跳上2級,跳3個,4個......n-1個。    //求該青蛙跳上一個n級的台階總共有多少種跳法    public int JumpII(int target){        if(target==0){            return 0;        }else if(target==1){            return 1;        }else if(target==2){            return 2;        }else{            int[] array = new int[target+1];            array[0]=0;            array[1]=1;            array[2]=2;            int sum = 3;            for(int i=3;i<array.length;i++){                array[i]=sum+1;                sum = sum+array[i];            }            return array[target];        }            }        public static void main(String[] args) {        // TODO Auto-generated method stub        JumpFloor jf = new JumpFloor();        System.out.println(jf.Jump(3));        System.out.println(jf.JumpII(3));    }}

這裡也是用偽遞迴來實現的

 

3. 遞迴的本質

其實遞迴的本質就是找到前後的聯絡,找到遞迴的公式

例如    F(n) = F(n-1) + F(n-2) 等等

 遞迴的一般情況是

(1). if(滿足遞迴結束條件),傳回值

(2). else,繼續遞迴

 

4. 回溯的本質,其實是在遞迴基礎上進行了改進

(1). if(不滿足繼續遞迴尋找的條件,通常是界限判斷),返回

(2). if(滿足尋找條件),記錄下來,繼續往下

(3). 加入這個節點,更新條件和值

(4). 遞迴左邊

(5).遞迴右邊

(6). 刪除這個節點(回溯)

來個例子,例子是中興的一道筆試題,我對其進行了改進。其實所有這類的能量補給,血條補給都是相同的解法。

import java.util.ArrayList;
//輸入//補給站個數,[補給站距離],[補給站能量],目的地距離(總共需要能量),初始能量//3, [5, 7, 10], [2, 3, 5], 15, 5//5, [10, 20, 22, 23, 26], [10, 2, 5, 1, 1], 30, 10
//輸出
//所有可以到達的方案,到達不了返回-1
import java.util.Arrays;import java.util.Scanner;public class PowerGain { private ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>(); private ArrayList<Integer> list = new ArrayList<Integer>(); public ArrayList<ArrayList<Integer>> minNumber(int n, int[] distince, int[] judce, int left, int right, int destination, int power){ //System.out.println(left+" "+destination+" "+power); if( left>right || power<=0){ return listAll; } //if(power>=distince[left]){ list.add(left); //} if(power>=destination){ listAll.add(new ArrayList<Integer>(list)); //return listAll; } int newleft = left+1; //不喝繼續前行,喝了繼續前行 minNumber(n, distince, judce, newleft, n, destination-distince[left], power-distince[left]); minNumber(n, distince, judce, newleft, n, destination-distince[left], power-distince[left]+judce[left]); list.remove(list.size()-1); return listAll; } public void outPrint(ArrayList<ArrayList<Integer>> tempAll){ if(tempAll.size()==0){ System.out.println(-1); return; } for(int i=0;i<tempAll.size();i++){ ArrayList<Integer> temp = tempAll.get(i); for(int j=1;j<temp.size();j++){ System.out.print(temp.get(j)); if(j!=temp.size()-1){ System.out.print(" "); } } System.out.println(); } } public static void main(String[] args) { // TODO Auto-generated method stub Scanner input = new Scanner(System.in); String st = input.nextLine(); String[] sarray = st.split(", "); int n = Integer.parseInt(sarray[0]); int[] distince = new int[n+1]; int[] judce = new int[n+1]; int index = 1; //sarray下標 for(int i=0;i<n;i++){ if(i==0){ distince[i] = Integer.parseInt(sarray[index].substring(1)); judce[i] = Integer.parseInt(sarray[index+n].substring(1)); }else if(i==n-1){ distince[i] = Integer.parseInt(sarray[index].substring(0, sarray[index].length()-1)); judce[i] = Integer.parseInt(sarray[index+n].substring(0, sarray[index+n].length()-1)); }else{ distince[i] = Integer.parseInt(sarray[index]); judce[i] = Integer.parseInt(sarray[index+n]); } index++; } index = 2*n+1; int destination = Integer.parseInt(sarray[index]); int power = Integer.parseInt(sarray[index+1]); //長度分段 judce[n] = 0; distince[n]=destination-distince[n-1]; for(int i=n-1;i>0;i--){ distince[i]=distince[i]-distince[i-1]; } PowerGain m = new PowerGain(){}; ArrayList<ArrayList<Integer>> result = m.minNumber(n, distince, judce, 0, n, destination, power); m.outPrint(result); }}

 

java——遞迴(動態規劃,回溯)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.