每日一道算法 | 【70. 爬楼梯】1、使用递归、动态规划、公式解决斐波那契数列问题

404 阅读2分钟

先上题目:

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

来源:力扣(LeetCode)

分析:

到楼顶,即最高阶的方法总数会等于“上一步是爬1阶”的方法总数和“上一步是爬2阶”的方法总数相加。每一阶都如此。

值得注意的是,上第一阶有1种方法,上第二阶有2种方法,上第三阶以及以上有“前两阶方法总数相加”的方法。

image.png 图片来源:图灵

解法:

这里提供了三个解法,分别是:递归、动态规划和斐波那契公式。

class Solution {

    //1.递归写法
    //直接使用递归会超时
    //使用数组/集合记录已经计算出来的数,减少重复计算的时间
    //时间复杂度:O(n)
     HashMap<Integer, Integer> map = new HashMap<>();
     public int climbStairs1(int n) {
         if(n == 1){
             return 1;
         }
         if(n == 2){
             return 2;
         } 
         if(map.get(n) != null){
             return map.get(n);
         } else{
             int result = climbStairs(n - 1) + climbStairs(n - 2);
             map.put(n, result);
             return result;
         }
     }

    //2.循环/动态规划写法
    //也可以使用数组,不过会增加空间复杂度
    //在c中,++i效率比i++高,因为i++多了一步(temp = i);而在java,二者都用到了中间值temp,即它们的效率是一样的。
    //时间复杂度:O(n)
     public int climbStairs2(int n) {
         if(n == 1){
             return 1;
         }
         if(n == 2){
             return 2;
         }
         int result = 0;
         int prepre = 1;
         int pre = 2;
         for(int i = 3;i <= n;i++){
             result = prepre + pre;
             prepre = pre;
             pre = result;
         }
         return result;
     }

    //3.斐波那契数列写法
    //斐波那契数列:第0个数为0,第一个数为1,第二个数为1,从第三项(2)开始,每一项都为前两项之和
    //时间复杂度:O(logn)
    public int climbStairs3(int n) {
        double sqrt_5 = Math.sqrt(5);
        double fib_n = Math.pow((1 + sqrt_5) / 2, n + 1) - Math.pow((1 - sqrt_5) / 2,n + 1);
        return (int)(fib_n / sqrt_5);
    }
}

附上:斐波那契公式:

image.png