当前位置: 首页 > news >正文

0-1背包问题 之 分割等和子集以及变形问题

文章目录

  • 416.分割等和子集
  • 3489.零数组变换IV

  • 0-1背包问题就是选择与不选择的问题,从根本上来讲的话,就是一个可以不连续的子集target问题,如果考虑的是一定得连续的问题,那么就可以考虑的是不定长滑动窗口的问题

416.分割等和子集

416.分割等和子集

在这里插入图片描述

  • 分割为两个等和的子集,那么我们可以转化为只用选择一个子集的问题,那么剩余的子集就是总和减去当前子集的和
  • 考虑到等和的问题,所以首先求解出sum(nums),如果为奇数,那么肯定是不能成功分解的,如果是偶数,就可以转化为,在原本的nums数组中,能否找到和为target//2的组合?
  • 注意dp数组的初始化,dp[i][0]都是True
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        # 其实就是0-1背包问题,target 是一半,所以sum得是偶数
        sumnums = sum(nums)
        if sumnums % 2 == 1:
            return False
        target = sumnums // 2
        n = len(nums)
        # 现在的话就是一个经典的0-1背包问题
        # 其实可以定义dp[i][j]表示为前i个物品中,是否可以组成j
        dp = [[True]+[False]*target for _ in range(n)]
        for i in range(n):
            for j in range(1,target+1):
                if j < nums[i] :
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i]]
        return dp[n-1][target]

3489.零数组变换IV

3489.零数组变换IV

在这里插入图片描述
在这里插入图片描述

  • 注意这个问题,我开始思考的是前缀和与差分,但是没考虑到题目中的选择范围是[l,r]的范围中的子集进行操作,那么就是说明对于每一个数的操作是独立的!
  • 只要我们在对应的操作数组中能够得到这个nums[i]的组合,那么就可以说明nums[i]是可以组合成功的,所以,我们可以转化为这个416.分割等和子集的问题,不过对应修改为能否在对应的pack[i]中得到nums[i]的组合?
class Solution:
    def minZeroArray(self, nums: List[int], queries: List[List[int]]) -> int:
        # 别人做的太复杂了,能不能直接转化为这个 subnums的问题
        n = len(nums)
        # 就是得开n个背包
        pack = [[] for _ in range(n)]
        m = len(queries)
        if sum(nums) == 0:
            return 0
        # 多个背包问题,然后求解的是是否都满足?都满足的情况下,找到最少的情况下的最大的那个所需的物品数
        def check(num,target):
            n1 = len(num)
            dp = [[True]+[False]*target for _ in range(n1)]
            for i in range(n1):
                for j in range(1,target+1):
                    if j < num[i]:
                        dp[i][j] = dp[i-1][j]
                    else:
                        dp[i][j] = dp[i-1][j] or dp[i-1][j-num[i]]
                if dp[i][target]:
                    return i+1
            return -1
        # 得到对应的一个物品的列表
        for l,r,v in queries:
            for i in range(n):
                if l<= i <=r:
                    pack[i].append(v)
                else:
                    pack[i].append(0)
        minans = 0
        for i in range(n):
            # 每一个背包都进行遍历
            cnt = check(pack[i],nums[i])
            if cnt == -1:
                return -1
            else:
                minans = max(minans,cnt)
        return minans

相关文章:

  • 嵌入式SDIO 总线面试题及参考答案
  • 验证与调参——交叉验证/ 网格搜索/贝叶斯优化/随机搜索
  • 第7章 站在对象模型的尖端3: RTTI
  • Skema:AI 驱动的方案到 BIM 加速工具,重塑早期设计工作流
  • 堆排序:力扣215.数组中的第K个大元素
  • 自画flink、spark源码学习流程大图分享
  • 【商城实战(36)】UniApp性能飞升秘籍:从渲染到编译的深度优化
  • 【JavaEE】IOC和DI
  • 一周热点:Compact Reasoning 精简推理
  • 实体多ID关联分页查询实例
  • Compose笔记(十一)--DataStore(二)
  • Day09 -实例:拿到加密密文进行解密
  • 【拒绝算法PUA】LeetCode 2270. 分割数组的方案数
  • Dijkstra解决单源最短路径
  • 2.1 transformer模型原理及代码(python)
  • 深度学习常用操作笔记
  • 多重背包讲解
  • 使用TensorFlow时需掌握的Pandas核心知识点
  • JDK15开始偏向锁不再默认开启
  • Qt开发——问界M9空调
  • 佩斯科夫:俄会考虑30天停火提议,但试图对俄施压无用
  • 重庆荣昌区委区政府再设“答谢宴”,邀请800余名志愿者机关食堂用餐
  • 习近平会见委内瑞拉总统马杜罗
  • 教育部答澎湃:2025世界数字教育大会将发布系列重磅成果
  • 中国德国商会报告:76%在华德企受美国关税影响,但对华投资战略依然稳固
  • 男子煎服15克山豆根中毒送医,医生:不能盲目相信偏方