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
- if j>=word_len and word == s[j-word_len:j] and dp[j-word_len]==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背包:一维数组 先遍历物品 再遍历背包 第二层逆向
- 完全背包:
- 排列:先遍历物品 再遍历背包
- 组合:先遍历背包 再遍历物品(物品的顺序每次不一样都需要增加到结果内)