LeetCode刷题笔记-70.爬楼梯(climbing-stairs)
问题描述
假设你正在爬楼梯。需要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 阶
题解
1.动态规划解法
算法解析
先从最基本情况分析,设f(n)表示上n阶台阶的走法个数:
n = 1时,f(1) = 1,第0阶\(\rightarrow\)第1阶跨1步为一种n = 2时,f(2) = 1 + 1 = 2,第0阶\(\rightarrow\)第1阶\(\rightarrow\)第2阶跨1步为一种,第0阶\(\rightarrow\)第2阶跨2步为一种n = 3时,f(3) = 1 + 2 = 3,第1阶\(\rightarrow\)第3阶跨2步为一种,第2阶\(\rightarrow\)第3阶跨1步为两种n = 4时,f(4) = 3 + 2,第3阶\(\rightarrow\)第4阶跨1步有三种,第2阶\(\rightarrow\)第4阶跨2步有两种
通过以上分析可以发现:若想走到第n阶台阶,无外乎两种情况:
- 从第
n-1阶台阶跨一步走到第n阶台阶,此时走法为f(n-1). - 从第
n-2阶台阶跨两步走到第n阶台阶,此时走法为f(n-2).
因此状态转移方程f(n)为:\(f(n) = f(n-1) + f(n-2)\)
至于状态转移方程为何不是\(f(n) = f(n-1)+1 + f(n-2)+2\)或者\(f(n) = f(n-1)+1 + f(n-2)+1\),是因为f(n)是爬楼梯方法数量,不是爬到n阶楼梯的步数,应该用乘法计算,即\(f(n) = f(n-1)*1 + f(n-2)*1\)
参考文章及资料
LeetCode官方题解 方法一:动态规划
LeetCode精选题解 第二种思路
复杂度分析
- 时间复杂度: \(O(N)\), 总计循环
n次 - 空间复杂度: \(O(1)\), 采用滚动数组时只需要固定的额外空间
代码实现
- Java版(滚动数组)
class Solution {
public int climbStairs(int n) {
int[] scrollArr = {0, 0, 1}; // 滚动数组,节约空间
for (int i = 0; i < n; ++i) {
scrollArr[0] = scrollArr[1];
scrollArr[1] = scrollArr[2];
scrollArr[2] = scrollArr[0] + scrollArr[1];
}
return scrollArr[2];
}
}
- Python版
class Solution:
def climbStairs(self, n: int) -> int:
dp = [0 for i in range(n+2)] # 未采用滚动数组
dp[1] = 1
dp[2] = 2
for i in range(3, n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
2.Fibonacci解法
观察动态图规划解法中的f(n)数字规律可以发现,f(n)就是斐波那契(Fibonacci)数列.因此本题也可以直接求Fibonacci数列.
算法解析
参考文章及资料
LeetCode官方题解 方法三:通项公式
百度百科:斐波那契数列
复杂度分析
- 时间复杂度: \(O(N)\),采用一般迭代法求
Fibonacci数列的时间复杂度为\(O(N)\),若采用公式法时间复杂度一般为\(O(logN)\) - 空间复杂度: \(O(1)\),只需要固定的额外空间
代码实现
- Java版(一般迭代法)
class Solution {
public int climbStairs(int n) {
int a = 0, b = 1, temp;
for (int i = 0; i < n; ++i) {
temp = b;
b = a + b;
a = temp;
}
return b;
}
}
- C版(一般迭代法)
int climbStairs(int n)
{
int i;
int a = 0, b = 1, temp;
for (i = 0; i < n; ++i)
{
temp = b;
b = a + b;
a =temp;
}
return b;
}
- Python版(一般迭代法)
class Solution:
def climbStairs(self, n: int) -> int:
a, b = 0, 1;
for i in range(n):
a, b = b, a+b
return b
- Python版(通项公式法)
class Solution:
def climbStairs(self, n: int) -> int:
sqrt5 = math.sqrt(5)
return round((pow((1+sqrt5)/2, n+1) - pow((1-sqrt5)/2, n+1)) / sqrt5)
注意:在使用公式法时,公式是从n=0开始计数,所以应该采用n+1计算n时Fibonacci数列值.
解题误区及心得总结
误区
- 在推导状态方程时,没有正确理解状态方程含义导致采用加法计算状态转移方程
心得总结
-
公式法求
Fibonacci数列 -
一般迭代法求解
Fibonacci数列的代码还可以更加优化(如下所示) -
C版(国际站讨论代码)
int climbStairs(int n)
{
int a = 1, b = 1;
while (n--)
a = (b += a) - a; // 很有技巧性
return a;
}
- Python版(国际站讨论代码)
a, b = 1, 1+n%2 # 减少了迭代次数
for i in range(int(n/2)):
a += b # 等价于: a = a + b
b += a # 等价于: b = (a + b) + b = a + 2b
return a
参考文章及资料
LeetCode-Discuss 3-4 short lines in every language
LeetCode-Discuss @qeatzy ⭐643 April 16, 2016 1:19 PM

浙公网安备 33010602011771号