刷题第三十六天 1049. 最后一块石头的重量Ⅱ 494. 目标和 474. 一和零

思路是尽可能分成重量相等的两堆,也就是取总和一半的的背包容量,装最大重量

class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        _sum = sum(stones)
        val = _sum // 2
        dp = [0] * (val + 1) #dp数组的含义为从石头中任取,装满容量为_sum//2的背包的最大重量,因为只有尽量装满_sum//2 剩下的一堆石头和背包里的石头就是最接近的
        for i in range(len(stones)):
            for j in range(val, stones[i] - 1, -1):
                dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]) 
        return _sum - 2 * dp[val]

dp数组的含义为从石头中任取,装满容量为_sum//2的背包的最大重量,因为只有尽量装满_sum//2 剩下的一堆石头和背包里的石头就是最接近的

能想到在nums中任取来装满容量为(sum(nums) - target)/2的背包,这些值需要变为负值

但是不知道该怎么求最大的方法数量

dp[j] 数组含义表示装满容量为j的背包有dp[j]种方法

装满容量为j的背包的总方法数量等于所有装满容量为j-nums[i]的背包方法数量之和。其中num[i]表示第i个物品的重量。

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        val = (sum(nums) - target) / 2               #在数组中哪些需要变为负值的元素和
        if val != int(val) or val < 0:               #如果这个和小于0或不为整数,说明找不到
            return 0
        val = int(val)
        dp = [0] * (val + 1)                         #dp数组含义,装满容量为j的背包有多少种方法
        dp[0] = 1
        for i in range(len(nums)):
            for j in range(val, nums[i] - 1, -1):
                dp[j] += dp[j - nums[i]]             #递推公式很关键,所有的装满背包最多有多少种方法问题通用
        return dp[val]

有一点思路:每个字符串就是一个物品,物品的价值就是1,有两个重量,一个重量就是0的数量 另一个重量就是1的数量。背包的容量也分为两部分。要同时装满背包的两个属性,求最大的价值,也就是子集最大的数量。

dp[i][j]: 装满i个0 j个1最多装多少个(dp[i][j])物品,最后返回dp[m][n]

class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        #dp[i][j] 最多有i个0和j个1的strs的最大子集的大小 m和n是背包容量,双容量
        #dp[i][j] = max(dp[i][j], dp[i - num_0][j - num_1] + 1)
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        for st in strs:                             #遍历物品
            num_0 = st.count('0')                   #count来统计0字符的个数
            num_1 = st.count('1')                   #1字符的个数
            for i in range(m, num_0 - 1, -1):       #遍历背包容量1
                for j in range(n, num_1 - 1, -1):   #遍历背包容量2
                    dp[i][j] = max(dp[i][j], dp[i - num_0][j - num_1] + 1)
        return dp[m][n]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值