代码随想录算法训练营第41天 |322.零钱兑换、279.完全平方数、139.单词拆分、多重背包例题

322.零钱兑换
https://leetcode.cn/problems/coin-change/description/
代码随想录
https://programmercarl.com/0322.零钱兑换.html#算法公开课
279.完全平方数
https://leetcode.cn/problems/perfect-squares/description/
代码随想录
https://programmercarl.com/0279.完全平方数.html
139.单词拆分
https://leetcode.cn/problems/word-break/description/
代码随想录
https://programmercarl.com/0139.单词拆分.html
多重背包例题
https://kamacoder.com/problempage.php?pid=1066
代码随想录
https://programmercarl.com/背包问题理论基础多重背包.html
背包问题总结
https://programmercarl.com/背包总结篇.html

322.零钱兑换

题解思路

  • 最小值;
  • 初始化为dp = [float('inf') * (amount+1)] dp[0]=0
  • 递推公式:dp[j] = min(dp[j-coins[i]]+1,dp[j])

题解代码

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        if amount<=0:
            return 0
        dp = [float('inf')]*(amount+1)
        dp[0]=0 ##初始:没办法拿硬币凑出金额0来

        for coin in coins:
            for j in range(coin,amount+1):
                dp[j] = min(dp[j-coin]+1,dp[j])

        if dp[-1]==float('inf'):
            return -1
        else:
            return dp[-1]

279.完全平方数

题解思路

  • 根号数是物品 dp[i][j]的第i个数的平方之前 和小于的j的数量
  • 递推公式:dp[j] = min(dp[j-add_num]+1,dp[j])

题解代码

class Solution:
    def numSquares(self, n: int) -> int:
        m = int(pow(n,1/2))
        dp = [float('inf')]*(n+1)
        dp[0] =0 
        print(f"m{m}")

        for i in range(1,m+1):
            add_num = i*i
            for j in range(add_num,n+1):
                dp[j] = min(dp[j-add_num]+1,dp[j])

        if dp[-1]==float('inf'):
            return -1
        else:
            return dp[-1]

139.单词拆分

题解思路

  • 单词是物品;整体是长度;
  • 递推条件是判断
    • if j>=word_len and word == s[j-word_len:j] and dp[j-word_len]==True:
      dp[j] = True
  • 是组合而不是排列,单词之间有顺序;

题解代码

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False]*(len(s)+1)
        dp[0] = True ##空字符串可以
        for j in range(0,len(s)+1):##组合不是排列 因为有顺序性
            for word in wordDict:
                if j>=len(word) and s[j-len(word):j] == word and dp[j-len(word)]==True:
                    dp[j] = True
        return dp[-1]

多重背包

题解思路

  • 思路和01背包一样
    • 区别:在01背包之后增加k次循环即可
    • 在将01里的1变成k循环

题解代码

def multibag(c,n,weight,value,nums):
    dp = [0]*(c+1)

    for i in range(n):
        for j in range(c,weight[i]-1,-1):##不重复
            for k in range(1,nums[i]+1):##个数值域:[1:nums[i]
                if k*weight[i]>j:
                    break
                dp[j] = max(dp[j-weight[i]*k]+value[i]*k,dp[j])

    return dp[-1]

背包问题总结

背包递推公式

  • 能否装满背包?(背包能装最大值)
    • dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
  • 装满有几种方法?(排列组合)
    • dp[j]+=dp[j-nums[i]]
  • 最大价值
    • dp[j] = max(dp[j],dp[j-weight[i]]+value[i])
  • 最小个数
    • dp[j] = min(dp[j],dp[j-coins[i]]+1)

遍历顺序

  • 01背包:一维数组 先遍历物品 再遍历背包 第二层逆向
  • 完全背包:
    • 排列:先遍历物品 再遍历背包
    • 组合:先遍历背包 再遍历物品(物品的顺序每次不一样都需要增加到结果内)
posted @ 2024-07-24 10:49  哆啦**  阅读(1)  评论(0编辑  收藏  举报