题目
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
Example:
Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
- 1 step + 1 step
- 2 steps
我的想法
brute force
按照题意把所有可能的组合遍历一次。结果对的,但是O(2^n)
超时
class Solution {
public int climbStairs(int n) {
return helper(n, 0, 0);
}
private int helper(int n, int sum, int count) {
if(sum + 1 <= n) count = helper(n, sum + 1, count);
if(sum + 2 <= n) count = helper(n, sum + 2, count);
if(sum == n) return ++count;
return count;
}
}
DP
把1~n之间每个数的解都求出来并存在dp数组中,
dp[i]
= dp[i-1] + dp[1]
= dp[i-2] + dp[2]
…
但是这样有重复项不知如何滤去
解答
leetcode solution 1: Brute force
同样也是超时,不过写法更漂亮
public class Solution {
public int climbStairs(int n) {
return climb_Stairs(0, n);
}
public int climb_Stairs(int i, int n) {
if (i > n) {
return 0;
}
if (i == n) {
return 1;
}
return climb_Stairs(i + 1, n) + climb_Stairs(i + 2, n);
}
}
leetcode solution 2: Recursion with Memoization
由上图可以看出,一个节点,如果值一定,其子孙节点一定。比如,当前节点为3,其子节点一定为4和5,再下一层一定为5,6,6,7。因此不管当前节点前面是如何连接的,只要节点的数值相同,则子孙节点情况一定相同。
因此,一旦某个节点满足条件的个数确定,其值可以复用。比如求值为5的情况,求得节点为4有1种情况,则不论其父节点是3还是2,都是1种情况。节点3有2种情况,则不论其是由1,1,1
,1,2
还是2,1
组成,其结果都是2。
在这里是从后往前的计算方法
public class Solution {
public int climbStairs(int n) {
int memo[] = new int[n + 1];
return climbHelper(n, memo, 0);
}
private int climbHelper(int n, int[] memo, int i) {
if(i == n) return 1;
if(i > n) return 0;
//如果当前值i已经计算过,直接用
if(memo[i] > 0) return memo[i];
//如果当前值i没有计算过,则先计算其子树的值
memo[i] = climbHelper(n, memo, i+1) + climbHelper(n, memo, i+2);
return memo[i];
}
}
leetcode solution 3: Dynamic Programming
这里像是将上一个方法的思想反过来,当前节点一定是由i-1和i-2,+1或者+2得来的,而与子孙节点无关。
自己差一点就做出来了,但是考虑的情况太多了,其实只需要考虑i-1和i-2。因为i-3、i-4,已经包括在了i-1和i-2的计算当中!!!!
最关键的点就是弄清楚什么是不变的量,在这里即为每个节点都只能由i-1和i-2,+1或者+2得到。
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}