当前位置 博文首页 > 庆述倾述:416. 分割等和子集

    庆述倾述:416. 分割等和子集

    作者:[db:作者] 时间:2021-08-05 12:45

    刷题记录第25题。本题地址:分割等和子集
    给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

    示例 1:

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

    示例 2:

    输入:nums = [1,2,3,5]
    输出:false
    解释:数组不能分割成两个元素和相等的子集。

    提示:

    1 <= nums.length <= 200
    1 <= nums[i] <= 100


    刚开始没有注意到子集不一定为连续,比如nums = [1,1,3,3]明显满足题意。

    看官方解析为0-1背包问题。在【labuladong】0-1背包问题详解视频中详细介绍了这个算法的分析和编码过程。

    也就是说其实这里面临的是转化问题,要将题目描述转化为0-1背包问题。

    比如nums=[1, 5, 11, 15]

    我们知道:

    • 数组分为两个和相等的子集,因为不包含小数,故而这里数组的sum一定为偶数;

    背包问题的基本定义为,对于二维数组dpdp[i][j]表示:
    对于前i个物品,当背包的容量为j的时候,可以装入背包的最大价值为dp[i][j]

    那么对于当前问题,nums=[1, 5, 11, 15],可以设当前物品分别为1,2,3,4nums即为对应价值。
    那么我们所求为背包总容量为sum/2的时候,是否恰好可装入的最大价值为sum/2

    观看视频我们知道,起状态转移方程为:

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

    因为j - nums[i - 1]在上式中为下标,表示背包的总价值,当价值小于0的时候,表示不可装入。那么就直接赋值为当前i个物品不装入,即上个物品的价值,表示如下:

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

    完整代码:

    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) { // 求总和
            sum += num;
        }
        if((sum & 1) == 1){  // 奇数
            return false;
        }
        int len = nums.length;
        int mid = sum / 2; // 最大价值
        int[][] dp = new int[len + 1][mid + 1];
        // len + 1 因为物品从1开始,而对应的价值下标为0开始
        // mid + 1 是因为还有背包容量为0的情况
        for (int i = 1; i <= len; i++) {
            for (int j = 0; j < mid + 1; j++) {
                if(j - nums[i - 1] < 0){
                    dp[i][j] = dp[i - 1][j];
                }else{
                    dp[i][j] = Math.max(dp[i - 1][j],
                            dp[i - 1][j - nums[i - 1]] + nums[i - 1]);
                }
            }
        }
        return dp[len][mid] == mid;
    }
    

    对于上面的案例nums=[1, 5, 11, 15],不妨这里将dp表格打印出来:

    0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	0	
    0	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	
    0	1	1	1	1	5	6	6	6	6	6	6	6	6	6	6	6	
    0	1	1	1	1	5	6	6	6	6	6	11	12	12	12	12	16	
    0	1	1	1	1	5	6	6	6	6	6	11	12	12	12	15	16	
    

    i=0表示前0个,当j=0表示背包容量为0。

    在这里插入图片描述

    cs
    下一篇:没有了