LeetCode [416. Partition Equal Subset Sum] 难度[medium]

题目:

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.
大概意思就是给出一系列数,问能不能把这些数分成两组,两组的和相等。

题目分析:

显然,这些数的和是可以求得的,所以每组之和也是知道的,当和为奇数时显然不成立。当和为偶数时,每组之和是总和的一半,问题转化为是否可以从这些数中找到一些数的组合,和刚好是这个和的一半。
这个问题和背包问题有点类似,解题思路也可以和背包问题类似,使用动态规划。用一个二维数组dp,dp[i][j]若为1表示第i个数之前,有和为j的组合。当读到第i个数时,若nums[i]>sum/2,则d[i][j] = d[i-1][j],否则d[i][j]=d[i-1][j] || d[i-1][j-nums[i]],所以最后的结果就是dp[nums.size][sum/2]。类比背包问题,这个题也可以用一维数组就可以实现,dp[i]若为1则表示存在和为i的组合,具体实现如下。算法的时间复杂度是O(MXN),M是sum/2,N是数字的数量。

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = accumulate(nums.begin(), nums.end(), 0);
        if(sum&1) return false;
        vector<int> dp(sum/2+1, 0);
        dp[0] = 1;
        for(int i = 0; i < nums.size(); i++)
        {
            for(int j = sum/2; j >= nums[i]; j--){
                 dp[j] = dp[j] || dp[j-nums[i]];
                 if(dp[sum/2])  return true;
            }
        }
        return dp[sum/2];
    }
};

本题除了使用动态规划解以外,也可以直接用递归算法来解,具体时间如下

class Solution {
public:
    bool getSum(vector<int>& nums, int sum, int start)
    {
        for(int i = start; i >= 0; --i)
        {
           if(nums[i] == sum)
             return true;
           if(nums[i] > sum)
             continue;
           if(getSum(nums,sum-nums[i],i-1))
             return true;
        }
        return false;
    }
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        int n = nums.size();
        if(!n)
           return true;
        for(int i = 0; i < n; ++i)
          sum += nums[i];
        if(sum%2)
           return false;
        sort(nums.begin(),nums.end());
        return getSum(nums,sum/2,n-1);
    }
};

有趣的是,本题使用递归算法,耗时远远低于使用DP算法,说明DP算法有时候效率也不高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值