1049. 最后一块石头的重量 II
https://leetcode.com/problems/last-stone-weight-ii/description/
思路:两块石头可以互相湮灭, 可以认为其是就是把所有的石头分成正负两组的符号。 例如石头是 [2, 4, 5], 可以认为最后最小的重量是 -(5-4) + 2 = +4 +2 -5 的组合。 那么要求这个问题, 可以回到01背包问题上了,设容量为 sum(stones) // 2 的背包, 看最大可以装多少重量的石头 设为x, 结果就是 sum(stones) - 2x。
难点: 思路上的转化
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
half = sum(stones) / 2
print(half)
dp = [[0] * (int(half) + 1) for _ in range(len(stones) + 1)]
for i in range(1, len(dp)):
for j in range(1, len(dp[0])):
if stones[i-1] > j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-stones[i-1]] + stones[i-1])
return int(2 * (half - dp[-1][-1]))
494. 目标和
https://leetcode.com/problems/target-sum/description/
思路:给定一个数组 nums 和 一个目标值 target。给数组的元素添加正负号, 问有多少种组合方式可以让数组的元素组合出目标值。 我们假设把数组的 的元素氛围pos 和 neg 组, sum(pos) + sum(neg) = sum(nums), sum(pos) - sum(neg) = target. 那么我们要找的其实就是sum(pos) = (sum(nums) + target) / 2 的组合方式。 然后问题转化成填满一个 (sum(nums) + target) / 2 的背包有多少方法。 注意这里是找组合方法, 所以明确dp数组的值表示的组合方法, 那么可以找到递推关系 dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i-1]]. 其中 dp[i-1][j]表示不放入i个元素可以填满j个背包的方法, dp[i-1][j-nums[i-1]]表示放入j 可以填满的方法。一维的关系就是 dp[i] += dp[i-nums[i-1]]. 然后数组的[0] 位置放入1, 表示[0] 有一种方法填满0容量的背包。
难点: 这个题怎么转变成背包问题我一开始是没想明白的, 看了卡哥的文档思路才恍然大悟。
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
'''
total_pos - total_neg = target
total_pos + total_neg = total_nums
the question equivlant to how many ways to pack a package of capacity total_pos with nums.
'''
if (sum(nums) + target) % 2 !=0 or abs(target) > sum(nums):
return 0
total_pos = int((sum(nums) + target) / 2)
dp = [0] * (total_pos + 1)
dp[0] = 1
for num in nums:
for i in range(total_pos, num-1, -1):
dp[i] += dp[i-num]
return dp[-1]
474.一和零
https://leetcode.com/problems/ones-and-zeroes/submissions/1201733711/
思路: 这个问题是一个更多维度的01背包问题, 首先明确问题要找的是满足条件的最大subset。 然后明确dp 数组中的值应该是最大subset 里面元素的个数。 然后回到01背包的问题中来, 当我们看到某个元素, 如果放进背包中, 那么它的最大元素个数就等于背包容量减去它分别占的 0, 1 的容量的最大元素个数加一, 或者不放入元素,等于前一个同位置的dp。 它和传统的01背包问题不同的是么传统的背包只有重量或者体积 这一个维度的容量, 但是这个问题有两维度。
难点: 要把一维的拓展到两维去考虑问题。
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
dp = [[0] * (m + 1) for _ in range(n+1)]
for s in strs:
c = Counter(s)
for i in range(n, c['1']-1, -1):
for j in range(m, c['0']-1, -1):
dp[i][j] = max(dp[i-c['1']][j-c['0']]+1, dp[i][j])
return dp[-1][-1]