假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。
示例1: 输入: 2 输出: 2 解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例2: 输入: 3 输出: 3 解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
使用动态规划解题
状态转移方程:
dp(n) = dp(n-1) + dp(n-2)
Base case:
当 n = 0 时,只有1种走法:dp(0) = 1
当 n = 1 时,同样也只有1种走法:dp(1) = 1
此时内心OS:这特喵的不就是斐波那契数列么,喂喂喂,禁止套娃啊
代码如下:
public int climbStairs(int n){if (n == 0) return 1;if (n == 1) return 1;return climbStairs(n - 2) + climbStairs(n - 1);}
优化
上面的代码在
LeetCode上直接运行会报超时而无法通过测试用例。
解决重叠子问题
这里使用dp table解决重叠子问题:
public int solution(int n) {int[] dp = new int[n + 1];dp[0] = 1;dp[1] = 1;for (int i = 2; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];}
状态压缩
通过状态转移方程我们可以很明确的看到,对于状态 dp(n)而言,它的值只与 dp(n-1)与dp(n-2)有关。因此,我们可以使用滚动数组压缩状态:
public int climbStairs(int n) {int p = 0, q = 0, r = 1;for (int i = 1; i <= n; ++i) {p = q;q = r;r = p + q;}return r;}
效率
- 经过优化后的空间复杂度:O(1)
- 经过优化后的时间复杂度:O(n)
