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

leetcode-分割等和子集

本题涉及到的是01背包问题,我将从两种解决背包问题的思路写出题解

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

乍眼一看可能看不出来和背包问题的联系,但是仔细想想,就是把nums的和分成一半,把一半当成背包,装nums里面的值,相等了另一半自然相等,既然如此首先这个nums的和就要满足是个偶数才能做到分割均匀,所以第一个判断就出炉了

        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (sum % 2 != 0) {
            return false;
        }

 判断完就开始准备对背包问题进行分析了

首先就是dp数组,这里dp[i][j]代表的就是从0-i这些元素里面取,j容量的背包能存的最大值

接下来就是递推公式:背包问题最重要的点就是能不能放得下,如果当前我们需要的值是j,j-nums【i-1】就是剩余的空间,如果放不下了就只能把刚才的值塞进了,如果还能放下,那就比较一下是刚才的值大还是当前值nums【i-1】加上剩余空间位置的最大值

 dp[i][j] = Math.max(dp[i - 1][j], nums[i-1] + dp[i - 1][j - nums[i-1]]);

最后就判断一下是否等于目标值就行。

因为我这里数组大小都加了1,所以不需要特意的初始化,直接都是0就行。

他的遍历顺序是从前往后的,因为我当前值是需要知道之前的值还有除了当前元素的最大空间,也就是想要得到当前值是需要上和左上方的值的!

上代码

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (sum % 2 != 0) {
            return false;
        }
        int m = nums.length;
        sum = sum / 2;
        int[][] dp = new int[m+1][sum+1];

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= sum; j++) {
                if (j - nums[i - 1] < 0) {
                    dp[i][j] = dp[i - 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], nums[i-1] + dp[i - 1][j - nums[i-1]]);
                }
            }

        }
        return dp[m][sum] == sum;
    }
}

第二种方式就是 给他降维,变成一维数组

这个时候dp数组就表示放进物品后,背的最⼤重量为dp[j],如果等于目标值了就说明装满了,而使用一维数组的时候物品遍历要放在外层,内层放的是背包,要倒序遍历

每到第i层,dp【i,nums【i】】是装不下当前物品的,所以不需要更新,从后往前遍历是因为dp需要比较当前值和nums值和剩余空间,如果从前往后,那么后面的值要依赖前面的值,所以可能会出现使用多次的情况

总结两点就是

  1. 从大到小遍历:确保在更新 dp[j] 时,dp[j - nums[i]] 是在当前物品之前的状态,避免重复使用物品。

  2. j >= nums[i] 的条件:只有当背包容量 j 大于或等于当前物品的重量 nums[i] 时,才可能将该物品放入背包,否则不需要更新 dp[j]

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int num:nums){
            sum+=num;
        }
        if(sum%2!=0){
            return false;
        }
        int[] dp = new int [sum+1];
        int target = sum/2;
        for(int i = 0;i<nums.length;i++){
            for(int j = target;j>=nums[i];j--){
                dp[j] = Math.max(dp[j],nums[i]+dp[j-nums[i]]);

            }
        }
        return dp[target] == target;
    }
}


http://www.kler.cn/a/526500.html

相关文章:

  • 网站快速收录:提高页面加载速度的重要性
  • 【16届蓝桥杯寒假刷题营】第2期DAY4
  • 信号处理以及队列
  • git push到远程仓库时无法推送大文件
  • 使用 Context API 管理临时状态,避免 Redux/Zustand 的持久化陷阱
  • Vue-day2
  • Java中 instanceof 的用法(详解)
  • 安卓(android)饭堂广播【Android移动开发基础案例教程(第2版)黑马程序员】
  • 谭浩强C语言程序设计(4) 8章(上)
  • deepseek R1 14b显存占用
  • 【Block总结】HWD,小波下采样,适用分类、分割、目标检测等任务|即插即用
  • 【Block总结】CAA捕获远程上下文信息,增强特征提取的能力|即插即用
  • 哈希表实现
  • 缓冲区和c库的简单实现
  • 性能优化2-删除无效引用
  • kobject、kset和ktype的关系
  • 论文阅读(七):贝叶斯因果表型网络解释遗传变异和生物学知识
  • python | OpenCV小记(一):cv2.imread(f) 读取图像操作(待更新)
  • 春晚舞台上的智能革命:中美人形机器人技术对比与发展
  • 日志2025.1.30
  • 【深度分析】DeepSeek 遭暴力破解,攻击 IP 均来自美国,造成影响有多大?有哪些好的防御措施?
  • Spring AI 与企业级应用架构的结合
  • 举例说明python单利模式的必要性
  • 数论问题80
  • floodfill算法(6题)
  • Node.js——模块化(模块的基本概念、模块化的规范、包与NPM)