假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
刚拿到题的时候马上想到了递归,dfs,尝试每种走法判断其可能性,可能即count++,代码如下:
private static int count=0;
public void dfs(int step,int n){
if(step==n){
count++;
return;
}
if(step<n){
dfs(step+2,n);
dfs(step+1,n);
}
}
public int climbStairs(int n) {
dfs(0,n);
int current=count;
count=0; //使用全局变量保存结果,计算结束时要初始化count
return current;
}
上述代码也能跑对,但是时间复杂度太高O(2^n)。当n很小时还看不出区别,但是当n逐渐变大时,这种方法的效率成指数级递减。
第二种方法利用了动态规划。
所谓动态规划,即通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。
根据这道题,我们可以发现想到到达第i阶,共有两种方法:
1.在i-1阶的时候向上走1阶;
2.在i-2阶的时候向上走2阶。
那么就是说,到达第i阶的方法就等于到达第i-1阶与到达第i-2阶所有方法之和。
代码如下:
public int climbStairs(int n) {
if(n==1)return 1;
int[] count=new int[n+1];
count[1]=1;
count[2]=2;
for(int i=3;i<=n;i++){
count[i]=count[i-2]+count[i-1];
}
return count[n];
}
时间复杂度为O(n)。
上述代码中,count[0]=1,count[1]=2 从第三项开始,每一项都等于前两项之和,就想到了斐波那契数列,代码如下:
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int first = 1;
int second = 2;
for (int i = 3; i <= n; i++) {
int current= first + second;
first = second;
second = current;
}
return second;
}
}
时间复杂度也为O(n).