动态规划05 | ● *1049. 最后一块石头的重量 II ● *494. 目标和 ● *474.一和零

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

视频讲解:https://www.bilibili.com/video/BV14M411C7oV
https://programmercarl.com/1049.%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E7%9F%B3%E5%A4%B4%E7%9A%84%E9%87%8D%E9%87%8FII.html

  • 考点
    • 动态规划
    • 01背包
  • 我的思路
    • 无思路
  • 视频讲解关键点总结
    • 和昨天的题目416. 分割等和子集类似
    • 关键点,想找到最后相抵消的最小重量,可以转化为把石头分成尽可能重量相近的两堆,这样互相抵消差值最小,也就可以转化为求背包容量为整堆石头重量的一半、每块石头最多取一次的01背包问题
    • 动规五部曲
      • 一维数组dp[j]的含义是,当背包容量为 j 时,取前 i 个石头(i通过外层循环来取,替代原有的二维数组),能得到的不超过背包容量的最大值(可以等于)
      • 递推公式
        • dp[j] = max(dp[j], dp[j - weight[i]] + weight[i])(取当前石头和不取当前石头的较大者)
      • 初始化,dp初始化为0即可,因为背包容量为0时最大值就为0
      • 遍历顺序
        • 外层循环遍历元素 i ,内存循环遍历容量 j
        • 外层循环正向遍历,内层循环反向遍历(避免将同一元素计算两次)
      • 无需打印
  • 我的思路的问题
    • 无思路
  • 代码书写问题
    • 注意内层循环的停止位置
  • 可执行代码
class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        summation = int(sum(stones) / 2)
        dp = [0] * (summation + 1)
        for i in range(len(stones)):
            for j in range(summation, stones[i] - 1, -1):
                dp[j] = max(dp[j], dp[j - stones[i]] + stones[i])
        return sum(stones) - dp[-1] - dp[-1]

*494. 目标和

视频讲解:https://www.bilibili.com/video/BV1o8411j73x
https://programmercarl.com/0494.%E7%9B%AE%E6%A0%87%E5%92%8C.html

  • 考点
    • 动态规划
    • 01背包
  • 我的思路
    • 无思路
  • 视频讲解关键点总结
    • 关键点,如何转化为01背包问题?根据题意,我们需要从母数组里分出作为正数的数组和作为负数的数组,二者的差值为目标值,二者的和值为母数组的和值,这就可以构成一个二元一次方程组,之后求解得到正数数组的和值为(母数组和值+目标值)/ 2,则题目转化为已知背包容量(正数数组的和值),求从前 i 个元素里取值,能组成多少种填满该容量的组合
    • 动规五部曲
      • 一维数组dp[j]的含义是,当背包容量为 j 时,从前 i 个元素中取,填满背包有多少种取法
      • 递推公式
        • dp[j] = dp[j] + dp[j - nums[i]]
      • 初始化,dp[0]初始化为1,这是因为根据递推公式,后续的dp值要根据1来进行叠加,如果dp[0]为0的话结果会均为0
      • 遍历顺序
        • 外层循环遍历元素 i ,内存循环遍历容量 j
        • 外层循环正向遍历,内层循环反向遍历(避免将同一元素计算两次)
      • 无需打印
  • 我的思路的问题
    • 无思路
  • 代码书写问题
    • 注意,本题的target可能为负,因此在开头的判断要加abs
  • 可执行代码
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        summation = sum(nums)
        result = (summation + target) / 2
        if result < 0:
            return 0
        if result != int(result):
            return 0
        dp = [0] * (int(result) + 1)
        dp[0] = 1
        for i in range(len(nums)):
            for j in range(int(result), nums[i] - 1, -1):
                dp[j] = dp[j] + dp[j - nums[i]]
        return dp[-1]

*474.一和零

视频讲解:https://www.bilibili.com/video/BV1rW4y1x7ZQ
https://programmercarl.com/0474.%E4%B8%80%E5%92%8C%E9%9B%B6.html

  • 考点
    • 动态规划
    • 01背包
  • 我的思路
    • 思路比较模糊,但相比前几道题稍微有些进步
  • 视频讲解关键点总结
    • 关键点,本题本质是向一个二维背包里装东西,问装满背包最多能装多少件物品
      • 其中二维的两个维度分别是0的容量和1的容量,每件物品的重量即为0的个数和1的个数
    • 动规五部曲
      • 二维数组dp[j][k]的含义是,当背包容量为 j、k 时(即能容纳j个0和k个1),在前 i 个元素(字符串)里取元素填满背包最多能取多少个元素
      • 递推公式
        • dp[j][k] = max(dp[j][k], dp[j - nums_0[str]][k - nums_1[str]] + 1)(取当前元素填满背包的元素总数和不取当前元素填满背包的元素总数之中取最大值)
      • 初始化,dp[0][0]和后续的dp元素均初始化为0
        • 外层循环遍历元素 i ,内存循环遍历容量 j 和 k
        • 外层循环正向遍历,内层循环反向遍历(避免将同一元素计算两次)
      • 无需打印
  • 我的思路的问题
    • 思路还在构建
  • 代码书写问题
  • 可执行代码
class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        for stri in strs:
            nums_0 = 0
            nums_1 = 0
            for i in stri:
                if i == '0':
                    nums_0 += 1
                else:
                    nums_1 += 1
            for j in range(m, nums_0 - 1, -1):
                for k in range(n, nums_1 - 1, -1):
                    dp[j][k] = max(dp[j][k], dp[j - nums_0][k - nums_1] + 1)
        return dp[m][n]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值