小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目:
这是一个动态规划的入门题: 青蛙跳台阶
题解:
我是一只青蛙,我现在要去跳台阶。
别问我为什么跳台阶,要不是导演安排我去跳台阶,好好的当一只与世无争的青蛙它不香吗?我可太难了。
导演说,每次你可以爬1或2个台阶,你有多少种不同的方法可以爬到楼顶呢?我陷入了蛙生的思考。
我是一只思维简单的青蛙,我决定用简单的方法开始思考这个问题。
初始化状态
1)假设这个楼梯只有1阶,那么我只有1种方法:
一次跳1阶;
2)假设这个楼梯有2阶,那么我有2种方法:
跳1阶,再跳1阶;
跳2阶;
3)假设这个楼梯有3阶,那么我有3种方法:
跳1阶,再跳2阶;
跳1阶,跳1阶,再跳1阶;
跳2阶, 再跳1阶;
递推公式
我是一只聪明的青蛙,很快我就发现,事情其实并不简单;
前往楼梯顶部的最后一步,要么跳1阶,要么跳2阶;
根据这个思路,假设我要跳3阶楼梯,只要把最后跳1阶即(前面跳2阶楼梯的方法数)加上最后跳2阶(前面跳1阶楼梯的方法数)不就可以了吗?
即跳n阶楼梯的方法数=跳n-1阶楼梯的方法数+跳n-2阶楼梯的方法数
我突然发现,这不就是我学过的斐波那契数列吗?
别问青蛙为什么会知道这个,导演要我知道我有什么办法。
斐波那契数列可以用递归方法解决,但是递归会涉及大量的重复计算。
(什么是递归?这里有一个生动的视频帮助你理解:leetcode-cn.com/circle/arti…])
状态缓存
我是一只爱做笔记的青蛙,为了避免重复计算,因此每次跳台阶的方法数,我都会记下来,这样下次就不用再重复计算啦!用一个数组dp就可以解决这个问题,dp[n] = dp[n-1]+dp[n-2]
代码如下:
class Solution:
def numWays(self, n: int) -> int:
if n == 0:
return 1
if n <= 2:
return n
dp = [0]*n
dp[0] = 1
dp[1] = 2
for i in range(2,n):
dp[i] = dp[i-1]+dp[i-2]
return dp[n-1] % 1000000007
这种方法的时间复杂度是O(n),空间复杂度是是O(n)。
空间压缩
很快我又发现,我也不必把所有的记录都记起来,假设我3阶楼梯,我也只需要知道跳2阶和跳1阶的方法数是多少就可以算出跳3阶的方法数,因此每次只需要保留n-1阶和n-2阶的方法数。
代码如下:
class Solution:
def numWays(self, n: int) -> int:
if n == 0:
return 1
if n <= 2:
return n
a = 1
b = 2
for i in range(3,n+1):
t = b
b = a + b
a = t
return b % 1000000007
压缩空间后的时间复杂度是O(n),空间复杂度是是O(1)。
温馨提示
当n = 0时,其实算是一张特殊情况,这里按照题目要求,n=0时算一种方法数,所以按照题目要求返回1即可,不必太过纠结~
视频题解:
这是我之前做的一个视频题解: 青蛙跳台阶
喜欢的话就给我点个赞吧~