「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」。
题目:现有一个长为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];
}
该方法的时间复杂度为,空间复杂度也为,最终实际耗时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;
}
时间复杂度不变,空间复杂度变为。