一、跳台阶问题描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
解法一:构造二叉树(回溯)
将该问题的解法构造为一棵树,左子树遍历+1,右子树遍历+2;
当结点的台阶总数==target,则计数器+1;
若节点当前走过的setp总和已经超过target那么返回上一层,不计数。
缺点:复杂度高,没有进行剪枝的优化
public class Solution {
int count = 0;
public int JumpFloor(int target) {
int step = 0;
HelpCount(target,step);
return count;
}
//target为台阶数,step为青蛙已经跳的台阶数
public void HelpCount(int target, int step){
//当前路径满足,计数器+1,返回上一层
if(target == step) {count++; return;}
//当前节点超过target,不满足,直接返回上一层
if(target<step) return;
//构造树的过程,左右二叉树,实际上为左边走1步,右边走2步
for(int i=0;i<2;i++){
HelpCount(target,step+i+1);
}
}
}
解法二:转换为斐波那契数列(递归)
可以通过找规律来看,假设现在有5个台阶。
最后一步:
从4跳到5或者从3跳到5,那么从4跳到5的方法加上从3跳到5的方法数量,就是总的数量f(5)=f(4)+f(3);
问题转换为找到跳到3和跳到5的总数量,又可以分别看1,2和3,4的方法数量相加。f(4)=f(3)+f(2),f(3)=f(1)+f(2);
其实可以看到,是一个斐波那契数列,f(n)=f(n-1)+f(n-2);
优缺点:转化过程不易想到,转换后方法容易
public class Solution {
public int JumpFloor(int target) {
if(target<0) return 0;
else if(target==1) return 1;
else if(target==2) return 2;
else{
return JumpFloor(target-1)+JumpFloor(target-2);
}
}
}
解法三:转换为斐波那契数列(非递归)
优缺点:转化过程不易想到,转换后方法容易,且非递归的方法更快
public class Solution {
int count = 0;
public int JumpFloor(int target) {
if(target<0) return 0;
if(target==1) return 1;
if(target==2) return 2;
//用三个变量存储n-2 n-1 和n的数量
int first = 1;
int second = 2;
int third = 0;
//当有3个以上的台阶,开始计算
for(int i=3;i<=target;i++){
//当前值等于前两个值的和
third = first+second;
//将first和second向后移动一个单位
first = second;
second = third;
}
return third;
}
}
二、变态跳台阶问题描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解法一:构造n叉树
利用一的解法一中的思想,此时需要构造的是target叉树。不多做解释
44 ms 9244K
public class Solution {
int count = 0;
public int JumpFloorII(int target) {
int step = 0;
HelpCount(target,step);
return count;
}
//target为台阶数,step为青蛙已经跳的台阶数
public void HelpCount(int target, int step){
//当前路径满足,计数器+1,返回上一层
if(target == step) {count++; return;}
//当前节点超过target,不满足,直接返回上一层
if(target<step) return;
//构造树的过程,此时是一棵target叉树
for(int i=0;i<target;i++){
HelpCount(target,step+i+1);
}
}
}
解法二:分析产生规律(递归)
根据跳台阶问题,f(n) = f(n-1)+f(n-2)
那么当前变态跳台阶问题变为:f(n) = f(n-1)+f(n-2)+…+f(n-(n-1)) +f(n-n)
根据高数无穷级数知识可知:f(n)=2f(n-1),
若不记得这个公式可通过如下推导得出该结论:
f(n) = f(n-1)+f(n-2)+…+f(n-(n-1)) +f(n-n)
f(n-1) = f(n-2)+…+f(n-(n-1)) +f(n-n)
上下两个公式相减:也可以得到f(n)=2f(n-1)
17 ms 9396K
public class Solution {
public int JumpFloorII(int target) {
if (target <= 0) {
return 0;
} else if (target == 1) {
return 1;
} else {
return 2 * JumpFloorII(target - 1);
}
}
}
方法三:方法二的优化
上述问题 可以直接通过f(n)=2f(n-1)公式进行循环计算
12 ms 9396K
public class Solution {
public int JumpFloorII(int target) {
int n = 1;
for(int i =2;i<=target;i++){
//n记录的是上一次的个数,每次循环*2即可
n=n*2;
}
return n;
}
}
方法四:对方法三的进一步理解
对于方法三初始1,一次循环后变为2,每次循环*2…循环n-1次
实际上就是2的n-1次幂
25 ms 9304K
public class Solution {
public int JumpFloorII(int target) {
if (target <= 0) {
return 0;
}
return (int)Math.pow(2,target-1);
}
}