416. Partition Equal Subset Sum 类似最小不可组成和

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Note:

  1. Each of the array element will not exceed 100.
  2. The array size will not exceed 200.

Example 1:

Input: [1, 5, 11, 5]

Output: true

Explanation: The array can be partitioned as [1, 5, 5] and [11].

Example 2:

Input: [1, 2, 3, 5]

Output: false

Explanation: The array cannot be partitioned into equal sum subsets.


Seen this question in a real interview before? 

把一个数组分成两组,看和是否相等。注意这不是连续数组。比如[3 4 6 5] 不能用区间和计算

思路:1个数选或不选。

首先求得总和,要求选其中的数的和是总和的一半。

建立矩阵dp[i][j],表示j这个和能否由前i个数组成。

边界条件: 

(1) dp[0][0]=true

(2)dp[i][0]=true,对于所有的i只要一个数都不选,就可以了

(3)dp[0][j]=false 0个数不能组成1一上的数,只能组成0

传递条件:

dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]]  说明,如果前i-1个数能组成j,那么前i个数一定能组成j,只要不加nums[i];如果前i-1个数能组成j-nums[i],那么前i个数能组成j,只要将nums[i]加上即可。这两种情况由一种满足,当前值就是true。

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int n=nums.size();
        if(n<=1) return false;
        int sum=accumulate(nums.begin(),nums.end(),0);
        if(sum&1) return false;
        sum/=2;
        vector<vector<bool>> dp(n+1,vector<bool>(sum+1,false));//这里的i,从1位置表示几个数,sum也是从1开始计算,因为0个数也要考虑,sum是求和的值,也包括0这个意义
        dp[0][0]=true;
        for(int i=1;i<=n;i++)
            dp[i][0]=true;
        //初始化dp[0][j]已经是false
        for(int i=1;i<=n;i++)
            for(int j=1;j<=sum;j++)
            {
                dp[i][j]=dp[i-1][j];//
                if(j>=nums[i-1])//有等号,和可以是0
                {
                    dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i-1]];//注意nums[i-1]是从0开始记得
                }
            }
        return dp[n][sum];
        
    }
};
空间优化:

发现横坐标至于前面一行有关,而且j的遍历也是从小到大的。所以j应该从大到小更新,否则会覆盖旧知

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int n=nums.size();
        if(n<=1) return false;
        int sum=accumulate(nums.begin(),nums.end(),0);
        if(sum&1) return false;
        sum/=2;
        vector<bool> dp(sum+1,false);//这里的i,从1位置表示几个数,sum也是从1开始计算,因为0个数也要考虑,sum是求和的值,也包括0这个意义
        dp[0]=true;
        //初始化dp[0][j]已经是false
        for(int i=1;i<=n;i++)
            for(int j=sum;j>=1;j--)
            {
                if(j>=nums[i-1])//有等号,和可以是0
                {
                    dp[j]=dp[j]||dp[j-nums[i-1]];//注意nums[i-1]是从0开始记得
                }
            }
        return dp[sum];
        
    }
};







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值