LeetCode416. Partition Equal Subset Sum

版权声明:本文为博主原创文章,欢迎转载!转载请保留原博客地址。 https://blog.csdn.net/grllery/article/details/85311587

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.

题目:根据所给的一串元素,全为正数,判断是否能分为两个和相等的子集。

首先看到题目,首先第一直觉就是既然要求两个相等的子集,那么就可以先求出整个数组的和sum,然后在数组中选择若干元素是否能满足和为sum/2即可。

关键是怎么取元素,取多少个。简单的想法就是遍历所有的情况,用DFS。对每个元素分别考虑取和不取时的情况,当所有元素都判断过,则返回。但是在运行时间上超过了限制。Time Limits Exceeded。

#include <iostream>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;

class Solution3 {
public:
	bool canPartition(vector<int>& nums) {
		if (nums.size() == 1)
			return false;

		int sum = accumulate(nums.begin(), nums.end(), 0);
		if (sum % 2 != 0)
			return false;
		//只需找到所有元素和的一半 对应的组合即可
		sum /= 2;

		int result = DFS(nums, sum, 0);
		return result;
	}

private:
	int DFS(vector<int>& nums, int remain, int start) {
		if (start == nums.size())
			return remain == 0 ? 1 : 0;

		if (remain < 0)
			return 0;

		return DFS(nums, remain - nums[start], start + 1)
			+ DFS(nums, remain, start + 1);
	}
};

如果我们要判断n个元素中的子集是否能组成和为sum,那么对于nums中的每个元素,我们都需要考虑选择和不选择该元素时对sum的影响,假设现在在判断第i个元素,此时前i-1个元素所能组成的和的集合记为sum(i-1) = {sum1,sum2,...},如果取nums[i]时,那么sum(i) = {sum1+nums[i], sum2+nums[2],....},如果不取nums[i],那么sum(i)=sum(i-1) = {sum1,sum2,...},最终对于第i个元素,我们的和的集合更新为sum(i)={sum1,sum2,sum1+nums[i], sum2+nums[2],...}。

以上的分析造成集合sum(i)的大小是在不断扩大的,由于题目的特殊性,所有的元素均为正数,由此我们知道集合sum(i)中的元素肯定也都是正数,同时我们需要求的是在sum(i)这个集合中是否存在target,因此我们可以事先将sum集合的范围设置为[0,target],如果前面集合出现了超过target的和,那么这个和对于我们来说是没用的,因为后面的元素在这个和的基础上进行操作的话必然也是会大于target的。

因此可以设置一个二维的数组dp[nums.size()+1][target+1],dp[i][j]表示前i个元素是否是组合成和为j,如果能的话则值为true,否则为false。

dp[i][j] = dp[i-1][j]

扫描二维码关注公众号,回复: 4739952 查看本文章

dp[i][j] = dp[i-1][j-nums[i]].

https://github.com/abesft/leetcode/blob/master/416PartitionEqualSubsetSum/416PartitionEqualSubsetSum.cpp

#include <iostream>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;


class Solution {
public:
	bool canPartition(vector<int>& nums) {
		if (nums.size() == 1)
			return false;

		int sum = accumulate(nums.begin(), nums.end(), 0);
		if (sum % 2 != 0)
			return false;
		//只需找到所有元素和的一半 对应的组合即可
		sum /= 2;

		//dp[i][j]表示当前数组中的前i个元素是否能组成和为j
		vector<vector<bool>> dp(nums.size() + 1, vector<bool>(sum + 1));

		dp[0][0] = true;

		for (int i = 1; i < nums.size() + 1; i++) {
			dp[i][0] = true;
		}

		for (int j = 1; j < sum + 1; j++) {
			dp[0][j] = false;
		}

		for (int i = 1; i < nums.size() + 1; i++)
		{
			for (int j = 1; j < sum + 1; j++)
			{
				dp[i][j] = dp[i - 1][j];
				if (j - nums[i - 1] >= 0)
					dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i - 1]];
			}
		}

		return dp[nums.size()][sum];
	}
};

class Solution2 {
public:
	bool canPartition(vector<int>& nums) {
		if (nums.size() == 1)
			return false;

		int sum = accumulate(nums.begin(), nums.end(), 0);
		if (sum % 2 != 0)
			return false;
		//只需找到所有元素和的一半 对应的组合即可
		sum /= 2;

		//dp[i]表示当前数组中是否有相应的组合的和的值为i
		vector<int> dp(sum + 1, false);

		dp[0] = true;

		for (size_t i = 0; i < nums.size(); i++)
		{
			//注意这里是反向
			for (int j = sum; j > 0; j--)
				if (j >= nums[i])
					dp[j] = dp[j] || dp[j - nums[i]];
		}

		return dp[sum];
	}
};

int main()
{
	Solution sln;
	vector<int> testcase{ 1,2,5 };
	cout << sln.canPartition(testcase) << endl;
	std::cout << "Hello World!\n";
}

参考:https://leetcode.com/problems/partition-equal-subset-sum/discuss/90592/01-knapsack-detailed-explanation

猜你喜欢

转载自blog.csdn.net/grllery/article/details/85311587