LeetCode 70.爬楼梯

116 阅读2分钟

「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。

题目:现有一个长为n的楼梯,每次你可以爬一个或者2个台阶,问如果要爬到楼顶,有多少种方法?

解题思路

看到本题第一眼我就又有印象了,这是组合数学中的一道例题,忘了是什么例题,但解题思路还记得。如果每次可以爬一个或者两个台阶,那么最终到终点的可能也只有这两种情况,那此时可以假设最终有f(n)f(n)种方法可以到达楼顶,最终的情况无非就是剩下一个台阶或者两个台阶,那如果最后一步是走的一个台阶,则前面可能的方法有f(n1)f(n-1)种,如果最后一步走的是两个台阶,则前面可能的方法有f(n2)f(n-2)种,那么最终可能的方法共f(n)=f(n1)+f(n2)f(n)=f(n-1)+f(n-2)种,有点像斐波那契数列,代码也很简单,使用简单的递归就能写出来,如下:

public int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        return climbStairs(n-1) + climbStairs(n-2);
    }

可惜超时了,我们可以换一种思路,上面方法超市的原因是当n很大的时候,递归栈中存储的数很多,并且存在严重的重复计算,此时必然很耗费资源,我们可以利用一个容器将每个中间结果存起来,如果已有了结果则不需要重复计算,此时就引入动态转移数组,用动态规划的方法来解决。

新创建的数组长度和n一样大,数组中元素i的含义是从首元素开始到数组中第i个位置存在多少种可能,此时状态转移方程和上面的递推公式一样,只需根据这个递推式来更新状态转移数组即可,代码如下:

public int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        int[] dp = new int[n];
        dp[0] = 1;
        dp[1] = 2;
        for(int i=2;i<n;i++){
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n-1];
    }

该方法的时间复杂度为O(N)O(N),空间复杂度也为O(N)O(N),最终实际耗时0ms,击败百分之百Java提交用户。实际上可以进一步优化空间复杂度,如下代码:

public int climbStairs(int n) {
        if(n==1) return 1;
        if(n==2) return 2;
        int temp1=1;
        int temp2=2;
        int temp3=0;
        for(int i=2;i<n;i++){
            temp3=temp1+temp2;
            temp1=temp2;
            temp2=temp3;
        }
        return temp3;
    }

时间复杂度不变,空间复杂度变为O(1)O(1)