LeetCode刷题——70. 爬楼梯
原创
©著作权归作者所有:来自51CTO博客作者愤怒的可乐的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目
假设你正在爬楼梯。需要 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 阶
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/climbing-stairs
思路
对于这样一个问题,我们先来思考下能否递归的解决,它内部是否有递归的结构。
我们自顶向下的思考问题,直接考虑第阶台阶,并且假设它下面的阶,阶等子问题都已经解决了。
如果我们要想爬上阶台阶,因为一次要么爬阶,要么爬阶,所以爬阶台阶有两种可能。
从阶再爬阶或者从阶再爬阶。
不难看出这是一个递归问题,我们把问题转换为爬阶有多少种方法和爬阶有多少种方法。然后把这两个问题的答案相加就好了。这样把一个大的问题转换为两个小问题。
用同样的思路可以求出爬阶和爬阶的方法数。从上面这个递归树可以看出,存在很多重复子问题。
下面我们先写出按照这种思路解决问题的递归算法。
代码
递归
class Solution:
def climbStairs(self, n: int) -> int:
# 递归的终止条件
if n == 1:
return 1
if n == 2:
return 2
return self.climbStairs(n-1) + self.climbStairs(n-2)
虽然思路是对的,但是递归的方式是比较低效的,这里导致了计算超时。参阅LeetCode刷题之动态规划思想,我们可以将其改成记忆化搜索的方式,解决重叠子问题。
因为爬2阶台阶有2种方法,和斐波那契数列很像。这里的递归终止条件还可以写成
if n == 0: return 1if n == 1:
return 1
这样这个问题就是斐波那契数列的应用。
记忆化搜索
dp = {}
class Solution:
def climbStairs(self, n: int) -> int:
# 递归的终止条件
if n == 0:
return 1
if n == 1:
return 1
if n not in dp: # 如果没有计算过再去计算
dp[n] = self.climbStairs(n-1) + self.climbStairs(n-2)
return dp[n]
最后改成动态规划也就很简单了。
动态规划
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
dp = [1] * (n+1) #dp[0] = 1 , dp[1] = 1 ,dp[2]以后的通过下面的式子计算
for i in range(2,n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
动态规划不需要递归求解,是一种自底向上的求解思想。