代码随想录算法训练营第三十六天 |动态规划part04
1049 最后一块石头的重量II
思路:sum = 23 sum//2 = 11 尽量凑11,如果凑成和12相撞,剩1
-
确定dp数组以及下标的含义
- dp[j] : 装满容量为j的背包的最大重量是dp[j]
-
递推公式
- 0-1背包:dp[j] = max(dp[j],dp[j-weight[i]]+value[i])
- dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
-
dp数组如何初始化
- target = sum(stones) // 2
- dp = [0] * (target + 1)
-
遍历顺序
- 如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
-
打印dp数组
- return (sum - dp[target]) - dp[target]
target = sum(stones) // 2
dp = [0] * (target + 1)
for i in range(len(stones)):
for j in range(target,stones[i]-1,-1):
dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
return sum(stones) - 2 * dp[target]
16 目标和
# left : + 之和
# right : - 之和
left + right = sum
left - right = target
right = sum - left
left - (sum - left) = target
left = (target + sum) / 2
如果 (target + sum) / 2 不是整数,那就说明找不出来 return 0
left : 背包容量
-
确定dp数组以及下标的含义
- dp[j] 装满容量为j的背包有dp[j]种方法
-
递推公式
- dp[j] += dp[j-nums[i]]
-
dp数组如何初始化
- dp[0] = 1
-
遍历顺序
-
for num in nums:
for j in range(left, num - 1, -1):
dp[j] += dp[j - num] # 其实就是放每个物品的情况做一个累加
-
-
打印dp数组
- return dp[target_sum] # 返回达到目标和的方案数
if sum(nums) < target :
return 0
if (sum(nums) + target) % 2 == 1:
return 0
t = (sum(nums) + target) // 2
if t < 0:
return 0
dp = [0] * (t + 1)
dp[0] = 1
for num in nums :
for j in range(t,num-1,-1) :
dp[j] += dp[j-num]
return dp[-1]
17 一和零
0-1背包:每个元素只能使用一次
-
确定dp数组以及下标的含义
- dp [i] [j] : 装满i个0 j个1 大小的背包最多背了dp [i] [j] 个物品(元素)
-
递推公式
- 0-1背包: dp[j] = max(dp[j],dp[j-weight[i]] + value[i])
- 物品的重量: x 个 0 y 个 1
- dp[i] [j] = max(dp [i-x] [j-y] + 1 , dp[i] [j])
-
dp数组如何初始化
- dp [0] [0] = 0
- 全都初始化成0 这样就不会影响dp[i] [j]
-
遍历顺序
- 先遍历物品,再遍历背包,背包要倒序遍历。
for strr in strs:# 遍历物品
x , y = 0 , 0
for i in strr:
if i == 0:
x += 1
else :
y += 1
for i in range(m,x-1,-1): # 遍历背包容量
for j in range(n,y-1,-1):
dp[i] [j] = max(dp [i-x] [j-y] + 1 , dp[i] [j])
-
打印dp数组
- return dp [m] [n]
完整代码:
dp = [[0] * (n + 1) for _ in range(m + 1)] # 创建二维动态规划数组,初始化为0
for s in strs: # 遍历物品
zeroNum = s.count('0') # 统计0的个数
oneNum = len(s) - zeroNum # 统计1的个数
for i in range(m, zeroNum - 1, -1): # 遍历背包容量且从后向前遍历
for j in range(n, oneNum - 1, -1):
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1) # 状态转移方程
return dp[m][n]