leetcode刷题-动态规划06

代码随想录动态规划part06|322. 零钱兑换、279.完全平方数、139.单词拆分

    • 322. 零钱兑换
    • 279.完全平方数
    • 139.单词拆分
    • 关于多重背包,你该了解这些!
    • 背包问题总结篇!

322. 零钱兑换

leetcode题目链接
代码随想录文档讲解

思路

完全背包整理:

  1. 完全背包理论基础:装满这个背包可得的最大价值(遍历顺序可以颠倒)
  2. 零钱兑换2:装满背包有多少种方法(每种方法不强调顺序,组合数)(先遍历物品再遍历背包)
  3. 组合总和4:装满背包有多少种方法(每种方法强调顺序,排列数)(先遍历背包再遍历物品)
    本题求,装满背包最少用多少件物品

动态规划五部曲

  1. dp[j]数组的含义:装满容量为j的背包的最少物品数量为dp[j],最终求dp[amount]
  2. 递推公式:dp[j] = min(dp[j], dp[j-coins[i]]+1)
    dp[j-coins[i]]+1代表放物品i,数量+1
  3. 初始化,dp[0]=0,非零下标初始化为INT_MAX
  4. 遍历顺序,考不考虑顺序都可以,不会影响最小值,所以怎么遍历都可以

python代码

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')]*(amount+1)
        dp[0] = 0
        for i in range(len(coins)):
            for j in range(coins[i], amount+1): //避免下标出现负数
                dp[j] = min(dp[j], dp[j-coins[i]]+1)
        return dp[amount] if dp[amount]!= float('inf') else -1

279.完全平方数

leetcode题目链接
代码随想录文档讲解

思路

与上题类似

动态规划五部曲

  1. dp[j]数组的含义:和为j的完全平方数的最少数量为dp[j],最终求dp[n]
  2. 递推公式:dp[j] = min(dp[j], dp[j-coins[i]]+1)
  3. 初始化,dp[0]=0,dp[1]=1,非零下标初始化为INT_MAX
  4. 遍历顺序,考不考虑顺序都可以,不会影响最小值,所以怎么遍历都可以

python代码

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float('inf')]*(n+1)
        dp[0] = 0
        dp[1] = 1 // 第一次没加这行,出现报错,测试样例为1
        nums = []
        for i in range(n):
            nums.append(i*i)
        for i in range(len(nums)):
            for j in range(nums[i], n+1):
                dp[j] = min(dp[j], dp[j-nums[i]]+1)
        return dp[n]
# 代码随想录答案
class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float('inf')] * (n + 1)
        dp[0] = 0

        for i in range(1, int(n ** 0.5) + 1):  # 遍历物品
            for j in range(i * i, n + 1):  # 遍历背包
                # 更新凑成数字 j 所需的最少完全平方数数量
                dp[j] = min(dp[j - i * i] + 1, dp[j])
        return dp[n]
 
class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float('inf')] * (n + 1)
        dp[0] = 0

        for i in range(1, n + 1):  # 遍历背包
            for j in range(1, int(i ** 0.5) + 1):  # 遍历物品
                # 更新凑成数字 i 所需的最少完全平方数数量
                dp[i] = min(dp[i], dp[i - j * j] + 1)
        return dp[n]

139.单词拆分

leetcode题目链接
代码随想录文档讲解

思路
可以用回溯算法暴力搜索
动态规划方法:
字符串s为背包,字符串列表为物品

  1. dp[i]=true,长度为i的字符串s能被字符串列表组成,最终结果为dp[s.size]
  2. 递推公式:if [j,i] & dp[j]==true: dp[i]=true
  3. 初始化:dp[0] = true,下标非0的dp[i]初始化为false
  4. 遍历顺序:这里字符串s对于列表中的元素组成是有顺序的,就是排列数,先遍历背包再遍历物品

python代码

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False]*(len(s)+1)
        dp[0] = True
        for i in range(1, len(s)+1):
            for j in range(i):
                if dp[j] == True and s[j:i] in wordDict:
                    dp[i] = True
        return dp[len(s)]
# 代码随想录,写法二
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False]*(len(s) + 1)
        dp[0] = True
        # 遍历背包
        for j in range(1, len(s) + 1):
            # 遍历单词
            for word in wordDict:
                if j >= len(word):
                    dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
        return dp[len(s)]

关于多重背包,你该了解这些!

多重背包代码随想录

背包问题总结篇!

总结篇代码随想录

你可能感兴趣的:(leetcode,动态规划,算法)