Day 43 | 动态规划 05

69 阅读2分钟

1049. 最后一块石头的重量 II

减法运算,求和

def lastStoneWeightII(self, stones: List[int]) -> int:
    # 小的被粉碎 大的变为y-x
    # 尽量让石头分成重量相同的两堆
    # 相当于寻找最接近sum的一半的值
    s = sum(stones)
    # 如果sum不为2的倍数 s//2会得到比较小的部分总和
    weight = s//2
    # 二维dp
    dp = [[0] * (weight+1) for i in range(len(stones))]
    for i in range(len(stones)):
        for j in range(weight+1):
            if j >= stones[i]:
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-stones[i]]+stones[i])
            else:
                dp[i][j] = dp[i-1][j]
    # print(dp)
    return s-2*dp[-1][-1]
    # 一维dp
    # dp = [0] * (weight+1)
    # for i in range(len(stones)):
    #     for j in range(weight,stones[i]-1,-1):
    #         dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
    # print(dp)
    return s-2*dp[-1]

494. 目标和

转化为01背包问题:

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

求组合类问题的公式:

dp[j] += dp[j - nums[i]]

重点在问题到01背包的转换,如何设置物品size和背包容量

def findTargetSumWays(self, nums: List[int], target: int) -> int:
    # 符合条件的个数
    # 相当于放入nums的数据 背包容量为target
    # 类比01背包 往背包里放物品 分析背包容量
    # 是否要放物品的操作0/1 类比本题的+/-
    s = sum(nums)
    # dp = [[s] * (len(nums)) for _ in range(target+1)]
    set_size = (s+target) // 2
    if abs(target) > s or (s + target) % 2 == 1: return 0
    dp = [0] * (set_size+1)
    dp[0] = 1

    for i in range(len(nums)):
        # 01背包内层倒序
        for j in range(set_size, nums[i]-1, -1):
            # dp[j] 符合和为j条件的个数
            dp[j] += dp[j-nums[i]]
    print(dp)
    return dp[-1]

474. 一和零

dp数组就表示当前i和j个0和1时 有多少种情况

把0和1的个数视为背包重量

def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
    # 最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1
    # 先把strs转化为 包含0,1的个数的列表
    dp = [[0] * (n+1) for _ in range(m+1)]
    count = []
    for s in strs:
        zeros = s.count('1')
        ones = s.count('0')
        if zeros <= m and ones <= n:
            dp[zeros][ones] = 1
        else:
            continue
        # 其实相当于两个维度都是背包容量
        # 两个一维滚动数组 从后遍历
        for i in range(m,-1,-1):
            for j in range(n,-1,-1):
                if i >= zeros and j >= ones:
                    dp[i][j] = max(dp[i][j], dp[i-zeros][j-ones] + 1)
    print(dp)
    return dp[m][n]