題1:斐波那契數列
題目描述:
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 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:放蘋果
題目描述:
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 }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。