牛客剑指offer——跳台阶/变态跳台阶

一、跳台阶问题描述:

一只青蛙一次可以跳上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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值