假设你正在爬楼梯。需要 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 阶
fib数列 多种解法
思路一:暴力递归
- 时间复杂度 O(2^n)
- 空间复杂度,即递归树深度n,O(n)
def climbStairs(n):
return n if n<=2 else climbStairs(n-1)+climbStairs(n-2)
思路二: 递归 + 记忆化
def climbStairs(n):
cache = {1:1, 0:1}
for i in range(2,n+1):
cache[i] = cache[i-1] + cache[i-2]
return cache[n]
climbStairs(10)
89
写一个做缓存的装饰器
def memo(fun):
cache = {}
def wrap(*args):
if args[0] not in cache:
cache[args[0]] = fun(*args)
return cache[args[0]]
return wrap
@memo
def climbStairs(n):
return n if n<=2 else climbStairs(n-1)+climbStairs(n-2)
climbStairs(10)
89
思路三:动态规划
第 i 阶可以由以下两种方法得到:
在第 (i-1)阶后向上爬 1 阶。
在第 (i-2)阶后向上爬 2 阶。
到达第 i 阶的方法总数就是到第 (i-1) 阶和第 (i-2) 阶的方法数之和。
def climbStairs(n):
dp = [0,1]
for _ in range(n):
dp[0],dp[1] = dp[1],dp[0]+dp[1]
return dp[1]
climbStairs(10)
89
def climbStairs(n):
a,b = 0,1
for _ in range(n):
a,b = b,a+b
return b
climbStairs(10)
89
思路四:fib数列递推公式
- 时间复杂度 O(logn),pow() takes logn
- 空间复杂度O(1)
def climbStairs(n):
import math
sqrt5 = math.sqrt(5)
fib = pow((1 + sqrt5) / 2, n+1) - pow((1 - sqrt5) / 2, n+1)
return int(fib/sqrt5)
climbStairs(10)
89
思路五:fib数列的快速幂算法 使用矩阵和LeetCode050 pow(n, n)思想
- 时间复杂度 O(logn) 因为可以采用快速幂算法(leetcode050 pow(x,n))
- 空间复杂度 O(1)
def mul(a, b): # 首先定义二阶矩阵乘法运算
c = [[0, 0], [0, 0]] # 定义一个空的二阶矩阵,存储结果
for i in range(2): # row
for j in range(2): # col
for k in range(2): # 新二阶矩阵的值计算
c[i][j] += a[i][k] * b[k][j]
return c
def fib(n):
if n <= 1: return max(n, 0)
res = [[1, 0], [0, 1]] # 单位矩阵,等价于1
A = [[1, 1], [1, 0]] # A矩阵
while n:
if n & 1: res = mul(res, A) # 如果n是奇数,或者直到n=1停止条件
A = mul(A, A) # 快速幂
n >>= 1 # 整除2,向下取整
return res[0][0]
fib(10)
89
爬楼梯变种,给出每次步长,eg: steps = [1, 2, 3] 求几种方法上 N 阶台阶
@memo
def climbBTStairs(n, steps):
cnt = 0
if n == 0:
cnt = 1
elif n > 0:
for step in steps:
cnt += climbBTStairs(n-step, steps)
return cnt
climbBTStairs(10, [1,2,3])
274