1049. 最后一块石头的重量 II
面试回来补卡,AC了不多解释了!!
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
s = sum(stones)
capacity = s >> 1
length = len(stones)
dp = [0] * (capacity + 1)
for i in range(length):
for j in range(capacity, stones[i] - 1, -1):
dp[j] = max(dp[j], dp[j - stones[i]] + stones[i])
return s - 2 * dp[capacity]
494. 目标和
本题比较难理解。
首先要对题意进行变换,我们取集合pos都取正号,补集neg都取负号,那么由于pos + neg = sum, pos - neg = target, 可以得到 pos = (sum + target) / 2,问题转化为,求数组nums的子集pos的个数,使得sum(pos) = new target。
使用动态规划的角度思考本问题,二维dp情况下,dp[i][j]表示前i个元素中可以达到目标和j的子集数量,i从0个元素也就是空集开始,j从目标和0开始。
最难理解的是初始化:我们必须初始化第一行,即空集达到目标和0-j各有多少方法,显然空集只有自己能达到目标和0,对于目标和1 - j,空集的子集数都是0个。
递推公式,dp[i][j]由两类情况得到,第一种i不放进去,达到目标和j的方法数等于dp[i-1][j],第二种可以放入i,达到目标和j的方法数等于dp[i - 1][j - nums[i]],根据加法原理,两者相加得到dp[i][j]。
遍历顺序:空集的情况已被初始化,我们从只有一个元素nums[0]开始遍历,而目标和需要从0开始遍历以应对nums[i] = 0的情况。因为nums[i]=0意味着dp[i - 1][j - nums[i]] = dp[i - 1][j],但是这是两种不同的方法分别对应nums[i]是否放入pos里面!!!还是需要求和!!!
二维dp:
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
s = sum(nums)
length = len(nums)
if (s + target) & 1: return 0
if abs(target) > s: return 0
capacity = (s + target) >> 1
dp = [[0] * (capacity + 1) for _ in range(length + 1)] #dp[i][j] 表示用0 - i个元素达到目标和j 有dp[i][j]种方法。
dp[0][0] = 1 #实际上这里是初始化第一行,0个元素达到目标和0有一种方法,0个元素达到目标和>0没有方法
for i in range(1, length + 1): #从第一个元素开始遍历
for j in range(capacity + 1):#目标和从0开始遍历
dp[i][j] = dp[i - 1][j]
if j >= nums[i - 1]:
dp[i][j] += dp[i - 1][j - nums[i - 1]]
return dp[length][capacity]
一维dp:
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
s = sum(nums)
length = len(nums)
if (s + target) & 1: return 0
if abs(target) > s: return 0
capacity = (s + target) >> 1
dp = [0] * (capacity + 1)
dp[0] = 1
for i in range(length):
for j in range(capacity, nums[i] - 1, -1):
dp[j] += dp[j - nums[i]]
return dp[capacity]
474. 一和零
三维dp数组:
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
l = len(strs)
dp = [[[0] * (n + 1) for i in range(m + 1)] for _ in range(l)]
z_0, o_0 = strs[0].count('0'), strs[0].count('1')
for j in range(m + 1):
for k in range(n + 1):
if z_0 <= j and o_0 <= k:
dp[0][j][k] = 1
for i in range(1,l):
z, o = strs[i].count('0'), strs[i].count('1')
for j in range(m + 1):
for k in range(n + 1):
if z <= j and o <= k:
dp[i][j][k] = max(dp[i - 1][j][k], dp[i -1][j - z][k - o] + 1)
else:
dp[i][j][k] = dp[i - 1][j][k]
return dp[l - 1][m][n]
每个价值都是1,背包有两个维度。
二维dp数组:
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
l = len(strs)
dp = [[0] * (n + 1) for i in range(m + 1)]
for s in strs:
z, o = s.count('0'), s.count('1')
for j in range(m, z - 1, -1):
for k in range(n, o - 1, -1):
dp[j][k] = max(dp[j][k], dp[j - z][k - o] + 1)
return dp[m][n]
今日总结:
目标和感觉代码随想录上的解释有一些错误。