分割等和子集 JAVA

日期:2020-10-11

作者:19届 LZ

标签:JAVA NP完全问题

题目描述

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

注意:

每个数组中的元素不会超过 100
数组的大小不会超过 200

示例:

示例 1:

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:

输入: [1, 2, 3, 5]

输出: false

解释: 数组不能分割成两个元素和相等的子集.

解题思路:

存在几种情况可以直接舍弃:
1,数组大小为1或0;
2,数组和为奇数
3,数组存在某个数大于数组和的一半

设立一个数组dp[i][j],表示是否可以从nunms[0]到nums[i]中选取元素使其和为j;

则以下条件恒成立
dp[i][0]=true;
dp[0][nums[0]]=true;

状态转移方程:
当i>0,j>0时:
如果nums[i]<=j,则dp[i][j]可以由dp[i-1][j-nums[i]]或者dp[i-1][j]得到
如果nums[i]>j,则dp[i][j]只能由dp[i-1][j]得到

代码

class Solution {
    public boolean canPartition(int[] nums) {
        int n=nums.length;

        if(n<2){//舍弃数组大小为1或0的情况
          return false;
        }

        int all=0,max=0;

        for(int num:nums){
            all+=num;
            max=Math.max(num,max);
        }

        if(all%2==1){//和为奇数,舍去
           return false;
           }

        int target=all/2;
             if(max>target)//舍弃存在一个数大于和的一半的情况
                return false;
        
        boolean[][] dp = new boolean[n][target + 1];
                   //dp[i][j]表示是否可以从nunms[0]到nums[i]中选取元素和为j


        for(int i=0;i<n;i++){
            dp[i][0]=true;//若不选取,和为0恒成立
        }
        dp[0][nums[0]]=true;//只能选择nums[0],所以恒成立

        for(int i=1;i<n;i++){   //状态转移方程
            for(int j=1;j<target+1;j++){
                if(nums[i]<=j){
                    dp[i][j]=dp[i-1][j-nums[i]]|dp[i-1][j];
                }
                else{
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
    
    return dp[n-1][target];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

中南大学苹果实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值