代码随想录算法训练营第四十三天丨1049. 最后一块石头的重量 II、494. 目标和

文章讲述了如何使用动态规划解决两个相关问题:目标和问题(计算满足条件的子集个数)和背包问题(找到可以形成最大价值的组合)。文章详细介绍了二维和一维dp的实现过程,以及如何正确初始化和更新dp数组。
摘要由CSDN通过智能技术生成

 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]

今日总结:

目标和感觉代码随想录上的解释有一些错误。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值