代码随想录算法训练营第三十八天

代码随想录算法训练营第三十八天| 理论基础,509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯

理论基础

经典题型

  • 背包问题
  • 打家劫舍
  • 股票问题
  • 子序列问题

动态规划步骤

  • 确定dp数组(dp table)以及下标的含义
  • 确定递推公式
  • dp数组如何初始化
  • 确定遍历顺序(for i 和for j到底是谁,到底谁先)
  • 举例推导dp数组(打印dp数组来debug)

509. 斐波那契数

题目链接:斐波那契数

递归

class Solution:
    def fib(self, n: int) -> int:
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            return self.fib(n-1)+self.fib(n-2)

动态规划

从五部曲开始:

  • 确定dp数组(dp table)以及下标的含义:dp[i],第i个斐波那契数;
  • 确定递推公式:dp[i] = dp[i-1]+dp[i-2];
  • dp数组如何初始化: dp[0] = 1; dp[1] = 1;
  • 确定遍历顺序:从前往后
  • 举例推导dp数组:用于debug
class Solution:
    def fib(self, n: int) -> int:
        if n==0: return 0
        dp = [0]*(n+1)
        dp[0] = 0
        dp[1] = 1
        for i in range(2,(n+1)):
            dp[i] = dp[i-1]+dp[i-2]
        return dp[-1]

但其实没必要维护一整个数组,维护三个数就行。

class Solution:
    def fib(self, n: int) -> int:
        if n==0: return 0
        if n==1: return 1
        a = 0
        b = 1
        c = 0
        for i in range(1,n):
            c = a+b 
            a = b 
            b = c 
        return c

70. 爬楼梯

题目链接:爬楼梯
如果是n节楼梯的爬法,就是n-1节楼梯的爬法(再往上一节),再加上n-2节楼梯的爬法(再直接往上两节)
n-2节楼梯的爬法之后两节其实有两种爬法,一种两次一节,一种直接上两节,但是上两次一节的其实已经包括在n-1节楼梯的爬法,再往上一节里了,所以n-2节楼梯的爬法之后两节直接考虑两节直接上就行
n=3: 1节的爬法(1)再直接往上两节+2节的爬法(2)再往上一节=3

递归

但是迭代会超时。

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            return self.climbStairs(n-1)+self.climbStairs(n-2)

因为你递归嵌套层数太多。这里在反复的self自引用,于是指数级上涨复杂度。这也是动态规划的优点所在。
需要动态规划。

动态规划

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1: return 1
        if n == 2: return 2
        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[-1]

同样也是可以只维护三个数。

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1: return 1
        if n == 2: return 2
        a = 1
        b = 2
        c = 0
        for i in range(2,n):
            c = a+b
            a = b
            b = c
        return c

746. 使用最小花费爬楼梯

题目链接:使用最小花费爬楼梯
和斐波那契也差不多,如果顶楼在i层,那么可以从i-1走一层到i,或者从i-2走两层到i
dp[i] = 爬到第i层的最低花费是多少。
又因为可以从底层也可以从一楼开始,那么dp[0]和dp[1]都不花钱都是0。
从二楼往后就是,从i-2楼出发的最小花费dp[i-2]+cost[i-2],和从i-1楼出发的最小花费dp[i-1]+cost[i-1],选择小的那个作为我们的最小花费。

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        #爬到第i层的最低花费是多少
        dp = [0]*(len(cost)+1)
        dp[2] = min(cost[0],cost[1]) #从0开始爬两层或者1开始爬一层
        for i in range(3,(len(cost)+1)):
            dp[i] = min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1])
        return dp[-1]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值