我是一只会动态规划的小青蛙

1,234 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目:

这是一个动态规划的入门题: 青蛙跳台阶

image.png

题解:

我是一只青蛙,我现在要去跳台阶。

别问我为什么跳台阶,要不是导演安排我去跳台阶,好好的当一只与世无争的青蛙它不香吗?我可太难了。

导演说,每次你可以爬1或2个台阶,你有多少种不同的方法可以爬到楼顶呢?我陷入了蛙生的思考。

我是一只思维简单的青蛙,我决定用简单的方法开始思考这个问题。

初始化状态

1)假设这个楼梯只有1阶,那么我只有1种方法:

一次跳1阶; image.png

2)假设这个楼梯有2阶,那么我有2种方法:

跳1阶,再跳1阶;

image.png

跳2阶;

image.png

3)假设这个楼梯有3阶,那么我有3种方法:

跳1阶,再跳2阶;

image.png

跳1阶,跳1阶,再跳1阶;

image.png

跳2阶, 再跳1阶;

image.png

递推公式

我是一只聪明的青蛙,很快我就发现,事情其实并不简单;

前往楼梯顶部的最后一步,要么跳1阶,要么跳2阶;

image.png

image.png

根据这个思路,假设我要跳3阶楼梯,只要把最后跳1阶即(前面跳2阶楼梯的方法数)加上最后跳2阶(前面跳1阶楼梯的方法数)不就可以了吗?

即跳n阶楼梯的方法数=跳n-1阶楼梯的方法数+跳n-2阶楼梯的方法数

我突然发现,这不就是我学过的斐波那契数列吗?

别问青蛙为什么会知道这个,导演要我知道我有什么办法。

斐波那契数列可以用递归方法解决,但是递归会涉及大量的重复计算。

(什么是递归?这里有一个生动的视频帮助你理解:leetcode-cn.com/circle/arti…])

状态缓存

我是一只爱做笔记的青蛙,为了避免重复计算,因此每次跳台阶的方法数,我都会记下来,这样下次就不用再重复计算啦!用一个数组dp就可以解决这个问题,dp[n] = dp[n-1]+dp[n-2]

image.png

代码如下:

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即可,不必太过纠结~

视频题解:

这是我之前做的一个视频题解: 青蛙跳台阶

喜欢的话就给我点个赞吧~