leetcode刷题记录【动态规划类题目】—Python代码+详细注释

题目:剑指 Offer 42. 连续子数组的最大和
难度:简单
算法:动态规划

# 2022.04.20
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # base case
        dp = [0] * (len(nums) )
        dp[0] = nums[0]
        ans = nums[0]
        for i in range(1, len(nums) ):
            dp[i] = max(dp[i - 1] + nums[i], nums[i])
            ans = max(ans, dp[i])
        return ans

题目:188. 买卖股票的最佳时机 IV
难度:困难
算法:动态规划

class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        # dp[i][k][0]
        # dp[i][k][1]
        # i base case:
        # dp[-1][k][0] = 0
        # dp[-1][k][1] = -inf
        # k base case:
        # dp[i][0][0] = 0
        # dp[i][0][1] = -inf
        if len(prices) == 0:
            return 0
        dp = [[[0] * 2] * k] * (len(prices))
        print(dp)
        for i in range(len(prices)):
            dp[i][0][0] = 0
            dp[i][0][1] = -inf
            for kk in range(1, k):
                if i - 1 == 0:
                    dp[i-1][kk][0] = 0
                    dp[i-1][kk][1] = -inf
                    continue
                # 状态转移方程
                # 现在没持有的话,要么是上期无且rest,要么上期有且本期卖掉
                dp[i][kk][0] = max(dp[i-1][kk][0], dp[i-1][kk][1] + prices[i])
                # 现在持有的话,要么是上期有且rest,要么是上期无且本期买
                dp[i][kk][1] = max(dp[i-1][kk][1], dp[i-1][kk-1][0] - prices[i])
        return dp[len(prices)-1][kk][0]

题目:322. 零钱兑换
难度:中等
算法:动态规划(取min值–最大最小问题)

# 2022.08.15
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [inf] * (amount + 1)
        dp[0] = 0
        # dp数组的范围都要+1
        # 两层循环也可以写成
        # for coin in coins:
        #     for i in range(coin, amount + 1):
        # 这样降低复杂度且节省了i-coin的比较
        for i in range(1, amount + 1):
            # 对每个coin都搜索一次,因为不限数量
            for coin in coins:
                # 判断一下,否则下面的dp[-coin]会越界
                if i - coin >= 0:
                    # 转移方程:dp[i]为需要达到i数额用到的金币数,dp[i-coin]为需要达到i减去当前coin数额用到的金币数
                    dp[i] = min(dp[i], dp[i - coin] + 1)
        return dp[amount] if dp[amount] != inf else -1

题目:518. 零钱兑换 II
难度:中等
算法:动态规划(取汇总值–组合问题)

# 2022.08.16
class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        # dp[i]为金额总和等于i的金币组合数
        dp = [0] * (amount + 1)
        # base case
        # dp[0] = 1,因为等于0的方案只有1个,就是什么coin都不选
        dp[0] = 1
        for coin in coins:
            for i in range(coin, amount + 1):
                # 把到每个dp从不同途径的coin组合起来的组合数累加起来
                dp[i] += dp[i - coin]
        return dp[amount]

# coin = 1
# dp[0] = 1
# dp[1] += dp[0] = 1
# dp[2] += dp[1] = 1
# dp[3] += dp[2] = 1
# dp[4] += dp[3] = 1
# dp[5] += dp[4] = 1

# coin = 2
# dp[2] += dp[0] = 2
# dp[3] += dp[1] = 2
# dp[4] += dp[2] = 3  # coin是2的时候,确定从amount=2可以到amount=4,那么就要看达到amount=2有几种方案
# dp[5] += dp[3] = 3

# coin = 5
# dp[5] += dp[0] = 4

题目:139. 单词拆分
难度:中等
算法:动态规划(True、False问题)
tips:看s在不在wordDict中,而不是wordDict在不在s中

# 2022.08.16
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        n = len(s)
        # 到j的时候,s[i:j]在wordDict中,那么追溯dp[i]也在wordDict里,则dp[j]也True
        dp = [False] * (n + 1)
        dp[0] = True
        # 注意i的范围,不能跟其他动态规划一样从1开始,因为后面有个s[i:j]的判断,要把s[0]也包含进去
        for i in range(0, n + 1):
            # j的范围从i开始或从i+1开始都可以,因为s[i:i]为空,会跳过
            for j in range(i + 1, n + 1):
                if dp[i] and s[i: j] in wordDict:
                    dp[j] = True
        return dp[n]

题目:121. 买卖股票的最佳时机
难度:简单
算法:动态规划

# 2022.09.08
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        # dp[i][0]为第i天的手上没股票的最大利润,dp[i][1]为第i天的手上持有股票的最大利润
        dp = [[0] * 2] * n
        # 不能用range(1, n+1),否则prices[i]的index会溢出
        for i in range(n):
            if i-1 == -1:
                dp[i][0] = 0
                dp[i][1] = -prices[i]
            # 当前没股票,那可能是上期有本期卖了,或上期没持有
            dp[i][0] = max(dp[i-1][1] + prices[i], dp[i-1][0])
            # 当前持有股票,那可能是上期没持有+本期买了,或上期有
            # 下面这个是错的,因为只有一次买卖机会,所以只要买了一次,默认当前的利润为- prices[i],否则会认为是叠加了之前的利润
            # dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1])
            dp[i][1] = max(- prices[i], dp[i-1][1])
        # 不需要return max(dp[n-1][0], dp[n-1][1]),因为如果到最后手里还持有股票没卖出的话,利润肯定没有卖出的高
        return dp[n-1][0]

题目:122. 买卖股票的最佳时机 II
难度:中等
算法:动态规划

# 2022.09.12
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if prices == sorted(prices, reverse = True):
            return 0
        n = len(prices)
        dp = [[0] * 2] * n
        # dp[i][1]当前有股票,上期无、本期购买,或上期有、本期无操作
        # dp[i][0]当前无股票,上期无、本期无操作,上期有,本期出售
        # dp[i][0/1]为第i期最大利润
        dp[-1][0] = 0
        dp[-1][1] = -prices[0]
        for i in range(n):
            dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1])
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
        return dp[n-1][0]
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值