劍指offer-裴波那切類遞歸,動態規划題總結


題1:斐波那契數列

題目描述:

大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項。

n<=39

思路:這類題一般都是遞歸,帶備忘的遞歸,動態規划這幾種做法

 1 public class Solution {
 2     public int Fibonacci(int n) {
 3         if(n==0)return 0;
 4         if(n==1||n==2)return 1;
 5         int pre=1;
 6         int cur=1;
 7         int next=0;
 8         for(int i=3;i<=n;i++){
 9             next=cur+pre;  
10             pre=cur;
11             cur=next;        
12         }
13         return next;
14     }
15 }

題2:跳台階

題目描述:

一只青蛙一次可以跳上1級台階,也可以跳上2級。求該青蛙跳上一個n級的台階總共有多少種跳法。

 思路:這次用遞歸做

1 public class Solution {
2     public int JumpFloor(int target) {
3         if(target<=1)return 1;
4         if(target==2)return 2;
5         return JumpFloor(target-1)+JumpFloor(target-2);
6     }
7 }

跳台階的同類題:

上台階:

有一樓梯共m級,剛開始時你在第一級,若每次只能跨上一級或者二級,要走上m級,共有多少走法?注:規定從一級到一級有0種走法。

給定一個正整數int n,請返回一個數,代表上樓的方式數。保證n小於等於100。為了防止溢出,請返回結果Mod 1000000007的值。

測試樣例:
3
返回:2
思路:這次用動態規划和矩陣快速冪,思路見我代碼里的注釋
 1 import java.util.*;
 2 /*
 3 典型的裴波那切問題,用遞歸或是循環都可解決,主要是要找到遞推關系式
 4 
 5  設x為要跳過的級數,f(x)為方式數
 6  當當前跳1級時,剩下的級數還有f(x-1)種
 7  當當前跳2級時,剩下的級數還有f(x-2)種
 8  所以總的方式有:f(x)=f(x-1)+f(x-2);
 9  利用此遞推式便可求出總的方式數
10  若采用矩陣快速冪法可先構造出初始矩陣
11  |1 1|   |f(x-1)|   |f(x)  |
12  |1 0| * |f(x-2)| = |f(x-1)|
13  由
14  |1 1|   |f(1)|   |f(2)|
15  |1 0| * |f(0)| = |f(1)|
16  |1 1|   |f(2)|   |f(3)|
17  |1 0| * |f(1)| = |f(2)|
18 ....
19 所以可得
20  {|1 1|}^(x-1)    |f(1)|   |f(x)  |
21  {|1 0|}       *  |f(0)| = |f(x-1)|
22 */
23 public class GoUpstairs {
24  /*   
25     public int countWays(int n) {
26         // 用動態規划
27         long dp[]=new long[n+1];
28         int m=1000000007;
29         dp[0]=0;
30         dp[1]=0;
31         dp[2]=1;
32         dp[3]=2;
33        for(int i=4;i<=n;i++){
34            dp[i]=(dp[i-1]+dp[i-2])%m;
35        }
36          
37         return (int)dp[n];
38            
39     }
40 */
41     public int countWays(int n) {
42         //用矩陣快速冪
43         long[][] base={{1,1},{1,0}};
44         long[][] unit={{1,1},{1,0}};
45      
46 /*   
47         while(n!=0){
48         if(n%2==1)
49             unit= matrixMultiple(unit,base);
50        else{
51             base= matrixMultiple(base,base);
52        }
53             n=n/2;
54         }
55  */
56         if(n<=1)return 0;
57         for(int i=1;i<n-1;i++){
58             base=matrixMultiple(base,unit);
59         }
60         return (int)(base[0][0]);
61     }
62     public  long[][] matrixMultiple(long[][] ret,long[][] base){
63         //這個函數實質上就是實現ret與base的矩陣相乘
64         long [][]tmp=new long [2][2];
65         for(int i=0;i<2;i++){
66             for(int j=0;j<2;j++){
67                 tmp[i][j]=(ret[i][0]*base[0][j]+ret[i][1]*base[1][j])%1000000007;
68             }
69         }
70         for(int i=0;i<2;i++){
71             for(int j=0;j<2;j++){
72                 ret[i][j]=tmp[i][j];}
73         }
74         return ret;
75          
76     }
77 }

 

題3;變態跳台階

題目描述:一只青蛙一次可以跳上1級台階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的台階總共有多少種跳法。

思路:最后一節階梯是必跳的,其他的都有跳或不跳兩種情況,所以總的方法數就是2^(n-1)

1 public class Solution {
2     public int JumpFloorII(int target) {
3         if(target==0)return 1;
4         return 1<<--target;
5     }
6 }

題4:放蘋果

題目描述:

把 M 個同樣的蘋果放在 N 個同樣的盤子里,允許有的盤子空着不放,問共有多少種不同的分法?
注意:5、1、1 和 1、5、1 是同一種分法,即順序無關。
輸入描述:
輸入包含多組數據。每組數據包含兩個正整數 m和n(1≤m, n≤20)。
輸出描述:
對應每組數據,輸出一個整數k,表示有k種不同的分法。
思路:
對於這個題,分兩種情況:
 
如果有空盤子,相當於我先拿出一個盤子不用,用剩下的盤子去裝蘋果,方法數為:dp[m][n-1]
如果沒有空盤子,相當於我先給每個盤子里放一個蘋果,然后再用剩下的蘋果去放盤子,方法數為:dp[m-n][n],不過在在此處要注意滿足m>=n,不然就會為負
對於m<n的情況,蘋果比盤子數還少,空盤子是沒用的,去掉空盤子,那就等同於在n個盤子里放n個蘋果
 
 
 
 1 import java.util.*;
 2 public class Main{
 3     private static final int  maxn=25;
 4     public static void main(String[] args){
 5         int [][]dp=new int[maxn][maxn];
 6         for(int i=0;i<maxn;i++){     
 7                 dp[i][1]=1;
 8                 dp[0][i]=1;
 9                 dp[1][i]=1;
10         }
11         for(int i=1;i<maxn;i++){
12             for(int j=2;j<maxn;j++){
13                 if(i>=j)
14                     dp[i][j]=dp[i][j-1]+dp[i-j][j];
15                 else if(i<j)
16                     dp[i][j]=dp[i][i];
17                 
18                 
19             }
20         }       
21         
22         Scanner sc=new Scanner(System.in);
23         while(sc.hasNext()){
24         int m=sc.nextInt();
25         int n=sc.nextInt();
26         int res=0;
27           
28            System.out.println(dp[m][n]);    
29     }
30 }
31 }
放蘋果題和整數划分類題是一樣的
整數划分:求將一個整數m至多划分成n個數有多少種情況
 
變形:求將一個整數m划分成n個數有多少種情況
dp[m][n] = dp[m-n][n] + dp[m- 1 ][n- 1 ]; 對於變形后的問題,存在兩種情況:   
     1 . n 份中不包含  1  的分法,為保證每份都 >=  2 ,可以先拿出 n 個  1  分到每一份,然后再把剩下的 m- n 分成 n 份即可,分法有: dp[m-n][n]        
     2 . n 份中至少有一份為  1  的分法,可以先那出一個  1  作為單獨的 1 份,剩下的 m-  1  再分成 n-  1  份即可,分法有:dp[m- 1 ][n- 1

 

題5:換零錢

題目描述:

有一個數組changes,changes中所有的值都為正數且不重復。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,對於一個給定值x,請設計一個高效算法,計算組成這個值的方案數。

給定一個int數組changes,代表所以零錢,同時給定它的大小n,另外給定一個正整數x,請返回組成x的方案數,保證n小於等於100且x小於等於10000。

測試樣例:
[5,10,25,1],4,15
返回:6
測試樣例:
[5,10,25,1],4,0
返回:1

思路:

這個題與之前做過的上樓梯,整數划分,籃子放蘋果等的同屬同一類題
對於上樓梯類題型,對於n層樓梯,上的方式較少,大多只有2,3種,比如一次上1層,或是一次上2層
則可以直接得到f(n)=f(n-1)+f(n-2);
使用帶備忘的遞歸,或是自底向上的dp都比較好解決
對於整數划分類題型,將一個整數n分成m個數相加的形式,求有多少種分法
直接對所分出的數中是否含有1,可得到2種情況
即dp[n][m]=dp[n][m-1]+dp[n-m][m]
對於此題,給定金額就好像是上面中待分的整數,只不過此時由於金額大小的限制,該整數只能由給定數組中的數組成

 

 1 import java.util.*;
 2 
 3 public class Exchange {
 4     public int countWays(int[] changes, int n, int x) {
 5         // write code here
 6         int [][] dp=new int[x+1][n];
 7         //dp[i][j]表示的是對於金額為i的,所給的錢的大小為change[0~j]中的數時,所對應的方案數
 8         for(int i=0;i*changes[0]<=x;i++){
 9             //第一列表示用大小為change[0]的錢去組成金額為i的方案數,
10             //可知,只有當金額為change[0]的倍數時,才存在有一種方案數
11             dp[i*changes[0]][0]=1;
12         }
13         for(int j=0;j<n;j++){
14             //第一行表示金額為0時,各個錢數的組成方案,可知都只有一種方案
15             dp[0][j]=1;
16         }
17         for(int i=1;i<=x;i++){
18             for(int j=1;j<n;j++){
19                 dp[i][j]=dp[i][j-1]+(i-changes[j]>=0?dp[i-changes[j]][j]:0);
20             }
21         }
22         return dp[x][n-1];
23     }
24 }

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com