题目:爬楼梯,每次可以爬1个或着2个台阶或者更多个台阶,共有几种爬法。
分析:这种题一般有两种做法,第一种是找规律。第二种是动态规划。
第一种:找规律法
假如题目是每次爬1个或者爬2个。求所有的可能性
首先我们先算出前十个的所有可能结果
台阶个数 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
可能情况 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 | 89 |
观察上表不难发现,从第三个台阶开始,当前的台阶数等于前两个数之和。这也就是斐波那契数列,得到这些信息后,编程就很容易了。
public static int F2(int n) { //输入n个台阶,返回所有种可能
if(n == 1) return 1;
if(n == 2) return 2;
int n1 = 1; //定义第一节台阶
int n2 = 2; //定义第二节台阶
for(int i = 0; i < n-2;i++) { //从第三节台阶开始,当前台阶数等于前两节之和
int temp = n1 + n2;
n1 = n2;
n2 = temp;
}
return n2;
}
假如题目是每次爬1个或者爬2个或者爬3个,求所有的可能数。
同样可以用上面的做法,先找规律。
台阶个数 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
可能情况 | 1 | 2 | 4 | 7 | 13 | 24 | 44 | 81 | 149 | 274 |
当然,找到第十个其实是非常麻烦的,一般找到第五个就差不多了。
显然也符合上面的规律,即从第四个数开始,当前数等于前三个数之和。
public static int F2(int n) { //输入n个台阶,返回所有的可能数 思想同上
if(n == 1) return 1;
if(n == 2) return 2;
if(n == 3) return 4;
int n1 = 1;
int n2 = 2;
int n3 = 4;
for(int i = 0; i < n-3;i++) {
int temp = n1+n2+n3;
n1 = n2;
n2 = n3;
n3 = temp;
}
return n3;
}
看到这里,之后的每次可以爬4阶、5阶…n阶的做法,都是同一种思路了。
第二种:动态规划
还是上面的第一题,每次可以爬1阶或者2阶,求共有几种爬法。
我们可以倒着推。最后一层台阶可以是从倒数第一层爬一阶楼梯上来的,也可以是从倒数第二层爬两层上来的。同理,倒数第一层台阶可以是从倒数第二阶爬一层上来的,也可以是从倒数第三层爬两层上来的…直到第二层可以从第一层爬一层上来,也可以是从地面爬两层上来。而第一层只能是从地面爬一层上来。
画图再解释一遍。假设n是4。
红色线表示每次爬一层,蓝色线表示每次爬两层。可以将该题转换成下楼梯,则需要在每层进行判断,当前层能否支持一次下一层,若支持则向下走一层,再判断当前层是否支持一次下两层,若支持,则下两层,若都不支持,则表示已经到地面了。接下来上代码。
public static int F(int n) { //输入n阶台阶 求所有可能性
if(n==0) return 1; //n为0 表示已经到地面了 这条路线就是一种可能性 则返回1
int sum = 0; //sum表示所有路线的和
if(n-1 >= 0) { //判断当前层能否支持向下走一层
sum += F(n-1); //向下走一层
}
if(n-2 >= 0) { //判断当前层能否支持向下走两层
sum += F(n-2); //向下走两层
}
return sum; //返回所有的可能
}
假如此时题目为:每次爬1个或者爬2个或者爬3个,求所有的可能数。
同理上述操作,我直接画图:
红色表示爬一层,蓝色表示爬两层,紫色表示爬三层。思想同上直接上代码。
public static int F(int n) { 输入n阶台阶 求所有可能性
if(n==0) return 1;
int sum = 0;
if(n-1 >= 0) { //判断当前层能否支持向下走一层
sum += F(n-1);
}
if(n-2 >= 0) { //判断当前层能否支持向下走两层
sum += F(n-2);
}
if(n-3 >= 0) { //判断当前层能否支持向下走三层
sum += F(n-3);
}
return sum;
}
则之后的每次可以爬n层都是这个思路,代码也大同小异。