原问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
分析:
思路一:问题可以简化为:n每次可以减1或者减2两种方式直到减到0为止,有多少种减法。可以得到一个二叉树:
现在问题就转化为数值为0的结点有多少个的问题。
思路一实现代码:
public int JumpFloor(int target) { //target表示楼梯阶数
if(target==0){
return 0;
}else{
return JumpCont(target);
}
}
public int JumpCont(int target){
if(target==0)
return 1;
else{
return JumpCont(target-1) + (target-2>=0 ? JumpCont(target-2):0); //注意:如果target-2<0了那就不能进入这个分支
}
}
思路二:动规
先思考当n=1时,显然只有一种上楼方法;当n=2时,有两种上楼方法;当n=3时,情形如下:
由图可知,当n=3又可以转化为n=1的情形加上n=2的情形,所以当n=3时,有1+2=3中上楼方法;当n=4时,又可以拆分为n=3和n=2的情形,所以有3+2中上楼方法;……
由这个规律可以得出一个规律是:假设f(target)是返回结果的函数,那么f(target) = f(target-1)+f(target-2);且当target=1时,f(target)=1;当target=2时,f(target)=2;这其实就是斐波那契数列数列,方法一其实就是斐波那契数列的递归求解方法。由公式可以创建一个数组来保存f(target-1)和f(target-2)的计算结果。
思路二代码实现:
public int JumpFloor(int target) {
if(target == 0)
return 0;
else if(target == 1){
return 1;
}else if(target == 2){
return 2;
}
int d[] = new int[target+1];
d[0] = 0;
d[1] = 1; //target=1时,只有一种上楼梯的方法
d[2] = 2; //target=2时,有两种上楼的方法
for(int i=3;i<=target;i++){
d[i] = d[i-1]+d[i-2];
}
return d[target];
}
进阶问题:
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析:只考虑动规,公式还是和前面一样,当n=1时,f(n)=1,表示只有一种跳法;当n=2时,f(n)=2,有两种跳法,注意当n=3时,f(3) = f(2) + f(1) + 1,这后面的加1表示加上一次跳3级的这种跳法;这样就可以得到公式:f(n) = f(n-1) + f(n-2) + 1;
代码实现:
public int JumpFloorII(int target) {
if(target==0)
return 0;
else if(target==1)
return 1;
else if(target==2)
return 2;
int[] dp = new int[target+1];
dp[0]=0;
dp[1]=1;
dp[2]=2;
int i=3,tmp;
for(;i<=target;i++){
tmp=0;
for(int j=1;j<i;j++){
tmp += dp[j];
}
dp[i] = tmp+1;
}
return dp[target];
}