剑指Offer:青蛙跳台阶问题

剑指Offer:青蛙跳台阶问题

题目描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

解题思路1:

  1. 这种题目关键是想到递归思想;
  2. 第一次跳楼梯,先跳1阶,剩余n-1阶未跳,定义剩余跳跃方法为:f(n-1)
  3. 第一次跳楼梯,先跳2阶,剩余n-2阶未跳,剩余跳跃方法为:f(n-2)
  4. 以此循环,每次都这样循环,定义好边界和初始条件:f(1)=1; f(2)=2;
  5. 因为每一次跳跃可以跳1阶或2阶,所以得出递归公式为:f(n)=f(n-1)+f(n-2);

注意:

  1. 编写递归代码的关键是,只要遇到递归,就把它抽象成一个递推公式,不用想一层层调用关系,不要试图用人脑去分解递归的每个步骤!
  2. 递归代码,重复计算的次数太多了,而且还存在堆栈溢出问题;
  3. 通过上面公式可以通过定义两个变量a,b,num=a+b;a是下一次的b,总和num是下一次的a,这样如此循环,可以说省去不断调用函数,增加的栈开销。
class Solution {
public:
    int numWays(int n)
    {
        if(n < 2) return 1;
        int num;
        int a=1, b=1;
        for(int i=2; i<n+1; i++)
        {
            num=(a+b)%1000000007;
            b=a;
            a=num;
        }
        return num;
    }
};

解题思路2:
递归代码转非递归,避免堆栈溢出。

    public int climbStairs(int n) {
        if(n <= 1)
            return 1;	//题目要求n=0,返回值也是1
        if(n==2)
            return 2;

        int* tmp = new int[n+1];
        //int[] tmp = new int[n+1];   //部分编译器支持这种写法
        tmp[1] = 1;
        tmp[2] = 2;
        for(int i=3;i<=n;i++){
            //n阶楼梯爬法拆解:第一步走了1阶+f(n-1)   第一步走了2阶+f(n-2)
            tmp[i] = tmp[i-1]+tmp[i-2];
        }
        return tmp[n];
    }

错误代码:
直接通过递归,不断调用函数,不断增加堆栈大小,最后超出时间限制;
系统栈或虚拟机栈空间一般不大,当递归规模比很大,调用层次很深,就会有栈溢出的风险。

class Solution {
public:
    int numWays(int n)
    {
        if(n <= 1)
        {
            return 1;
        }
        //if(n==1) return 1;
        if(n==2) return 2;
        return ways(n);
    }
    int ways(int n)
    {
        if(n <= 1)  return 1;
        if(n==2)    return 2;
        return (ways(n-1) + ways(n-2))%1000000007;
    }
};

参考链接:https://blog.csdn.net/ten_sory/article/details/64126341

posted @ 2020-02-21 12:06  Ternence_zq  阅读(145)  评论(0编辑  收藏  举报