代码随想录算法训练营第四十八天(动态规划篇之01背包)| 1049. 最后一块石头的重量Ⅱ,494. 目标和

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

题目链接:1049. 最后一块石头的重量 II - 力扣(LeetCode)

思路

尽量将石头分为重量相同的两堆,这样两堆中的石头相撞之后剩下的石头就会最小。根据之前的01背包理论:

代码随想录算法训练营第四十五天(动态规划篇)|01背包-CSDN博客

代码随想录算法训练营第四十六天(动态规划篇)|01背包(滚动数组方法)-CSDN博客

可以设背包容量为石头重量总和的一半,求它所能装的最大价值,之后就能得到最后所剩的石头。

代码实现

class Solution(object):
    def lastStoneWeightII(self, stones):
        G1 = sum(stones)//2   
        G2 = sum(stones) - G1 
        dp = [0] * (G1 + 1)
        for num in stones:
            for j in range(G1, num - 1, -1):
                dp[j] = max(dp[j], dp[j - num] + num)
        return (G1 - dp[G1] + G2) - dp[G1]
        
       # e.g.  分为33,34两堆,如果容量为33的背包所装的最大价值为31,那相撞后的那块石头质量为(33 - 31 + 34) - 31
        

494. 目标和

题目链接:494. 目标和 - 力扣(LeetCode)

思路

把数组里的数分为两部分:前面符号为“+”,即要被加的数,和前面符号为“-”,即要被减的数。设所有参与加法的数和为x,参与减法的数和为y,则x-y = target,x+y=sum,联立得x = (target+sum)/2。因此题目就变成了寻找数组中和为(target+sum)/2的子集总和,转变为01背包问题,即能将容量为(target+sum)/2背包装满的方法。

1. dp数组定义

dp[j]: 将容量为j的背包装满的方法。

2. 递推公式

遍历数组中的数,每遍历到新的数nums[i],相当于新加了一个物体,那么dp[j](能装满容量为j的包的方法)就会发生变化,之前的方法加上当前物体所能贡献的那部分,当前物体可以帮着填充容量为j-nums[i]的包。因此,dp[j]因为nums[i]的到来,多了dp[j-nums[i]]种新方法。

所以递推公式为dp[j] += dp[j-nums[i]]

3. 初始条件

当背包容量为0,有1种方法,即什么都不选,dp[0] = 1

4. 递推顺序

使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历。

5. 举例推导dp数组

输入:nums:[1, 1, 1, 1, 1], S:3

bagSize = (S + sum) / 2 = (3 + 5) / 2 = 4

dp数组状态变化如下:

代码随想录算法训练营第四十八天(动态规划篇之01背包)| 1049. 最后一块石头的重量Ⅱ,494. 目标和_第1张图片

对于第一个数字1,只能填满容量为0和容量为1的背包,当考虑到第二个1时,可能填满的背包容量为1到S = 3。如果要填满容量为3的背包,就要看看已有的物体有多少种填满容量为2的包的方法,但没有(dp[2] = 0),所以dp[3]只能保持为0。但新加入的物体1可以帮着填满容量为2的包,因为之前已经有一种方法可以装满容量为1的包了,因此dp[2] = 1。

代码实现

class Solution(object):
    def findTargetSumWays(self, nums, target):
        if abs(target) > sum(nums):   # 对于nums,最大能得到的数是全体非负整数相加,最小是最大值的负数,如果target超过次范围,则没有方法。
            return 0
        if (target + sum(nums))%2 == 1:
            return 0
        x = (sum(nums) + target)/2
        dp = [0] * (x + 1)
        dp[0] = 1
        for num in nums:
            for j in range(x, num - 1, -1):
                dp[j] += dp[j - num]
        return dp[x]

你可能感兴趣的:(代码随想录训练营,算法,动态规划,python,leetcode)