Leetcode刷题(22)动态规划专题:爬楼梯(重新包装的斐波那契数列,动态规划使用三部曲总结)

题目

70. 爬楼梯

在这里插入图片描述
在这里插入图片描述

难度:简单

题目分析:这道题是动态规划系列的第一个例题,因此,这里总结下使用动态规划的三部曲。
1. 定义数组 dp[n] 的含义,这个根据具体题目来赋予含义, 这道题是 台阶 n 拥有多少种走法
2. 找出更新数组的递归公式,比如这题是 d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] dp[n] = dp[n-1]+dp[n-2] dp[n]=dp[n1]+dp[n2], 这里含义是,台阶 n 可以是在 台阶 n-1 迈一步到达,也可以从台阶 n-2 迈两步到达。动态规划的含义就是充分利用之前的数据, 于是不难明白,dp[n-1] 和 dp[n-2]在计算dp[n]之前,取值必须刷新
3. 设置初始条件, 因为数组dp索引的含义是多少级楼梯,所以, n 要大于等于0。 当 n = 0 , 1 , n =0, 1, n=0,1,时,没法使用递推公式更新,因此呢,我们自己手算填入。

以上便是使用动态规划需要的三部曲。关键点是头两步,定义好数组代表的含义,以及找出递推公式,难点也正是这里。

适合使用动态规划的题目,一般都是问,最大值、最小值可以是多少,某某有多少种解法,这类题目,因此也可以使用基于队列的广度优先搜索(BFS)去做。使用动态规划,无法给出具体的操作,它只能告诉我们答案有多少。如果题目还需要输出具体步骤,那只能借助于BFS或DFS来求解。

1. 解法一:动态规划(正统解法)

class Solution:
    def climbStairs(self, n: int) -> int:
        if n < 2:
            return 1
        dp =[0]*(n+1) # 表示n个台阶有几种解法
        # 初始条件
        dp[1], dp[0]= 1, 1
        for i in range(2, n+1):
            dp[i] = dp[i-1] + dp[i-2]
        
        return dp[n]

1.1 运行结果

在这里插入图片描述
在这里插入图片描述

1.2 分析:

很奇怪,时间很慢。这里时间复杂度是 O(n), 空间复杂度也是O(n)。

考虑到每一个数字,最多使用两次,所以存储空间可以节省。 下面是使用O(1)空间复杂度的解法。

2. 解法二: 动态规划改进版

class Solution:
    def climbStairs(self, n: int) -> int:
    	# 使用O(1)的空间
        # 递推公式其实就是斐波那契数列
        if n < 2:
            return 1
        f0, f1 = 1, 1
        
        for i in range(2, n+1):
            f = f0 + f1
            f1, f0 = f, f1
        return f1

2.1 运行结果:

在这里插入图片描述
在这里插入图片描述

2.2 分析:

这个算法时间复杂度依然是 O(n)。

解法三:递归

class Solution:
    def climbStairs(self, n: int) -> int:
    	# 自然可以使用递归
        def fn(n):
            if n < 2:
                return 1
            return fn(n-1) + fn(n-2)
        
        return fn(n)

3.1 运行结果

在这里插入图片描述

3.2 分析:

斐波那契数列的爆炸式增长,大家是知道的, 输入是38,输出就是千万量级。
在这里插入图片描述
另外,单纯使用递归的话,嵌套层数会非常深,里面会有大量重复计算,因此,又是不能免俗的引进额外空间来辅助存储。其实也就回到了动态规划的解法。

3.3 改进:额外存储空间

f_array = [0]*(n+1)
        def fn(n,f_array):
            if n < 2:
                return 1
            if f_array[n]!= 0:
                return f_array[n]
            f_array[n] = fn(n-1, f_array) + fn(n-2, f_array)
            return f_array[n]
        
        return fn(n, f_array)
3.3.1 运行结果:

在这里插入图片描述
在这里插入图片描述

3.3.2 分析:

改进后代码,其实跟动态规划差别已经不大了,所以,这类题目,用递归的效益不高啊。

总结:

动态规划或许可以粗略的理解为带中间信息存储的递归算法,因为他们二者都充分利用规模更小问题的答案, 只是动态规划是在数组中递推,而不是函数调用。

上面的问题,其实就是斐波那契数列的求解,在数学上,还有时间复杂度是 O(log n)的解法,是最快的!不过由于不是本篇的重点,暂时不做讨论,有兴趣的可以点击以下链接到Leetcode官网看官方解释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值