假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
# 找出转移方程 f(x) = f(x-1) + f(x-2)
# f(1) = 1
# f(2) = 2
# f(3) = 3
# f(4) = 5
# 以此类推
# 1、递归 一般超时 方法解析 5->(3,4)(3->(1,2)) 4->(2,3) 3->(1,2)
# 计算了两次的3->(1,2)
# if n == 1:
# return 1
# if n == 2:
# return 2
# return self.climbStairs(n-1)+self.climbStairs(n-2)
# 2、为了解决重复计算了3(1,2)的问题 使用列表进行记录判断
# memo = [0 for _ in range(n+1)]
# # 结果分析
# [0, 0, 2, 0] func(n-1)执行 n==2 return 2
# [0, 1, 2, 0] func(n-2)执行 n==1 return 1
# [0, 1, 2, 3] func(n)执行 n==3 return 2+1=3
# def func(n): # 递归方法
# # 退出条件
# if memo[n] > 0: # 有记录的
# return memo[n]
# if n == 1:
# memo[n] = 1
# elif n == 2:
# memo[n] = 2
# else:
# memo[n] = func(n-1)+func(n-2)
# return memo[n]
# # 调用函数
# return func(n)
# 3、动态规划 记录了计算过的全部状态 但是只有dp[i-1] +dp[i-2]会被用到计算
# dp = [0 for _ in range(n+1)]
# dp[0] = 1
# dp[1] = 1
# # 迭代
# for i in range(2,n+1):
# dp[i] = dp[i-1] +dp[i-2]
# return dp[-1]
# 4、O(1)的空间复杂度设计 只需要存储dp[i-1] +dp[i-2] 滚动变换值
# 初始化的值决定了你的开始位置 对应的循环次数也要改变
# 值使用三个变量 为常数级别 空间复杂度为O(1)
# 与斐波那契数列一致 可以求某一项的值
# if n == 1: # 特殊条件可以去掉
# return 1
# q , p , r = 1 , 1 , 2 # q , p , r = 0 , 0 ,1
# for i in range(2 , n): # 2-->0
# q = p
# p = r
# r = q + p
# return r
# 5、矩阵快速幂
# 通过矩阵寻找递推关系 M = [[1,1][1,0]]
# [[f(n),[f(n-1)]]T * M = [[f(n)+f(n-1)],[f(n)]] = [[f(n+1)],[f(n)]]
# ...
# [[f(1)],[f(0)]] = [1,1]
# 因此不需要每次都去计算递推公式dp[i] = dp[i-1] +dp[i-2]
# 而是通过计算n次的M矩阵相乘即可
# (a * b) % p = (a % p * b % p) % p 求A的B次幂的最后三位
# /**
# * 普通的求幂函数
# * @param base 底数
# * @param power 指数
# * @return 求幂结果的最后3位数表示的整数
# */
# long long normalPower(long long base,long long power){
# long long result=1;
# for(int i=1;i<=power;i++){
# result=result*base;
# result=result%1000;
# }
# return result%1000;
# 快速幂计算 大大减少计算的次数
# 时间复杂度 O(logn) 空间复杂度 O(1) 用到了常数量的内存空间
# def pow1(a,n):
# res = [[1,0],[0,1]] # 初始化为单位矩阵
# while n > 0: # 循环logn次
# # n为奇数 提取1出来 1次方 是当前底数即矩阵M的一次方 放到结果中(相乘)
# if (n & 1) == 1: # n % 2 == 1
# res = matmul(res,a) # 矩阵乘法 行列元素对应相乘再相加
# n = n >> 1 # 指数减半 n = n // 2
# a = matmul(a,a) # 矩阵平方
# return res
# def matmul(a,b): # 常数量级
# c = [[0,0] for _ in range(2) ]
# for i in range(2):
# for j in range(2):
# c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j]
# return c
# 函数调用
# M = [[1,1],[1,0]] # 矩阵M
# res = pow1(M,n)
# return res[0][0]
# 6、通项公式计算
# 齐次递推关系公式通过特征根法计算得到通解 要了解求非齐次递归公式的通解
# 直接将n输入 得到对用的答案
# sqrt5 = pow(5,0.5)
# res = pow((1 + sqrt5) / 2, n + 1)-pow(( 1 - sqrt5) / 2, n + 1)
# return int(res / sqrt5)