背包九讲
01背包
特点:
每种物品只有一件,选择放/不放
状态转移方程
大循环是每个物品,小循环是价值
for i in range(1, n):
for j in range(ci, v+1):
dp[i][j] = max(dp[i-1][j], dp[i-1][j-ci])
优化
j从v到0,可以少一维数组
for i in range(1, n):
for j in range(v, 0, -1):
dp[j] = max(dp[j], dp[j-ci]+wi)
初始化
初始化要是,没有任何物品可以放的时候,依然合法。
要装满
初始值=负无穷大。
没东西放,就未定义
不一定装满
初始值=0
没东西放,价值为0
leetcode例子
416 分割等和子集
n件物品:len(nums)
容量v:sum(nums)//2
放入损耗ci:0
获得价值wi:nums[i]
装满:初始化为false
class Solution:
def canPartition(self, nums: List[int]) -> bool:
n = len(nums)
target = sum(nums)
if target % 2 != 0:
return False
target //= 2
dp = [[False]*(target+1) for _ in range(n)]
dp[0][0] = True
for i in range(1, n):
for j in range(0, target+1):
dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i]])
return dp[-1][-1]
Runtime: 3032 ms, faster than 5.11% of Python3 online submissions for Partition Equal Subset Sum.
Memory Usage: 16.4 MB, less than 9.09% of Python3 online submissions for Partition Equal Subset Sum.
class Solution:
def canPartition(self, nums: List[int]) -> bool:
n = len(nums)
target = sum(nums)
if target % 2 != 0:
return False
target //= 2
dp = [False]*(target+1)
dp[0] = True
for i in range(1, n):
for j in range(target, nums[i]-1, -1):
dp[j] = dp[j] or dp[j-nums[i]]
return dp[-1]
Runtime: 780 ms, faster than 48.92% of Python3 online submissions for Partition Equal Subset Sum. Memory Usage: 12.7 MB, less than 100.00% of Python3 online submissions for Partition Equal Subset Sum.
322 零钱兑换
每个硬币最多选择一次:
n件物品:len(coins)
容量v:amount
放入损耗ci:0
获得价值wi:coins[i]
装满:初始化为-1
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
m = amount
dp = [m+1]*(m+1)
dp[0] = 0
for c in coins:
for j in range(m, c-1, -1):
dp[j] = min(dp[j], dp[j-c]+1)
return dp[-1] if dp[-1] != (m+1) else -1
377 组合总和 Ⅳ
n件物品:nums
容量v:len(nums)
放入损耗ci:0
获得价值wi:num
不装满:初始化0
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
if not nums or target <= 0:
return 0
dp = [1]+[0]*target
for i in range(1, target+1):
for num in nums:
if i >= num:
dp[i] += dp[i-num]
return dp[-1]
Runtime: 40 ms, faster than 80.63% of Python3 online submissions for Combination Sum IV.
Memory Usage: 13.1 MB, less than 100.00% of Python3 online submissions for Combination Sum IV.
474 一和零
n件物品:m个0、n个1
容量v:len(strs)
放入损耗ci:-1
获得价值wi:str
不装满:初始化0
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
if len(strs) == 0:
return 0
dp = [[0]*(n+1) for _ in range(m+1)]
for item in strs:
item0 = item.count('0')
item1 = item.count('1')
for i in range(m, item0-1, -1):
for j in range(n, item1-1, -1):
dp[i][j] = max(dp[i][j], 1+dp[i-item0][j-item1])
return dp[m][n]
Runtime: 3068 ms, faster than 71.04% of Python3 online submissions for Ones and Zeroes. Memory Usage: 12.8 MB, less than 100.00% of Python3 online submissions for Ones and Zeroes.
139
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
maxlen = 0
for word in wordDict:
if len(word) > maxlen:
maxlen = len(word)
res = [0]*len(s)
for i in range(len(s)):
p = i
while p >= 0 and i-p <= maxlen:
if (res[p] == 1 and s[p+1:i+1] in wordDict) or (p == 0 and
s[p:i+1] in wordDict):
res[i] = 1
break
p -= 1
return res[-1]
Runtime: 32 ms, faster than 96.24% of Python3 online submissions for Word Break.
Memory Usage: 12.8 MB, less than 100.00% of Python3 online submissions for Word Break.
494 目标和
n件物品:所有正数num
容量v:(sum(nums)+S)//2
放入损耗ci:0
获得价值wi:num
不装满:初始化0
class Solution:
def findTargetSumWays(self, nums: List[int], S: int) -> int:
if sum(nums) < S or (sum(nums)+S) % 2 == 1:
return 0
v = (sum(nums)+S)//2
dp = [1]+[0]*v
for num in nums:
for j in range(v, num-1, -1):
dp[j] += dp[j-num]
return dp[v]
Runtime: 72 ms, faster than 98.96% of Python3 online submissions for Target Sum.
Memory Usage: 12.9 MB, less than 100.00% of Python3 online submissions for Target Sum.
完全背包
Last updated
Was this helpful?