leetcode刷题-动态规划06
代码随想录动态规划part06|322. 零钱兑换、279.完全平方数、139.单词拆分
- 322. 零钱兑换
- 279.完全平方数
- 139.单词拆分
- 关于多重背包,你该了解这些!
- 背包问题总结篇!
322. 零钱兑换
leetcode题目链接
代码随想录文档讲解
思路
:
完全背包整理:
- 完全背包理论基础:装满这个背包可得的最大价值(遍历顺序可以颠倒)
- 零钱兑换2:装满背包有多少种方法(每种方法不强调顺序,组合数)(先遍历物品再遍历背包)
- 组合总和4:装满背包有多少种方法(每种方法强调顺序,排列数)(先遍历背包再遍历物品)
本题求,装满背包最少用多少件物品
动态规划五部曲
- dp[j]数组的含义:装满容量为j的背包的最少物品数量为dp[j],最终求dp[amount]
- 递推公式:dp[j] = min(dp[j], dp[j-coins[i]]+1)
dp[j-coins[i]]+1代表放物品i,数量+1 - 初始化,dp[0]=0,非零下标初始化为INT_MAX
- 遍历顺序,考不考虑顺序都可以,不会影响最小值,所以怎么遍历都可以
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题目链接
代码随想录文档讲解
思路
:
与上题类似
动态规划五部曲
- dp[j]数组的含义:和为j的完全平方数的最少数量为dp[j],最终求dp[n]
- 递推公式:dp[j] = min(dp[j], dp[j-coins[i]]+1)
- 初始化,dp[0]=0,dp[1]=1,非零下标初始化为INT_MAX
- 遍历顺序,考不考虑顺序都可以,不会影响最小值,所以怎么遍历都可以
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为背包,字符串列表为物品
- dp[i]=true,长度为i的字符串s能被字符串列表组成,最终结果为dp[s.size]
- 递推公式:if [j,i] & dp[j]==true: dp[i]=true
- 初始化:dp[0] = true,下标非0的dp[i]初始化为false
- 遍历顺序:这里字符串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)]
关于多重背包,你该了解这些!
多重背包代码随想录
背包问题总结篇!
总结篇代码随想录