LeetCode416.分割等和子集

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

注意:

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

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

输出: true

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

示例 2:

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

输出: false

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

public static boolean canPartition(int[] nums) {
	//二维数组较一维数组空间利用率大,效率低,但是可以回溯,找到解的组成部分
	int len=nums.length;
	int sum=0;
	for(int i : nums) {
		sum+=i;
	}
	if(sum%2!=0) {
		return false;
	}
	sum/=2;
	int[][] dp=new int[len][sum+1];//dp[i]j]表示在前i个数字中,它们中取任意数相加在   不超过j情况下  所得到最大值
	for(int i=0;i<=sum;i++) {//第一行要单独求出
		if(nums[0]<=i) {
			dp[0][i]=nums[0];
		}
	}
	for(int i=1;i<len;i++) {       //第i个物品只有选或不选dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i];
		for(int j=1;j<=sum;j++) {//											
			if(j-nums[i]<0) {
				dp[i][j]=dp[i-1][j];
			}
			else {
				dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i]);
			}
		}
	}
	if(dp[len-1][sum]==sum) {
		return true;
	}
	return false;
}


public static boolean canPartition(int[] nums) {
	//一维数组 效率高,空间消耗少,但不能回溯,
	int len=nums.length;
	int sum=0;
	for(int i : nums) {
		sum+=i;
	}
	if(sum%2!=0) {
		return false;
	}
	sum/=2;
	
	//优化思路
	//dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i];
	//dp[i][j]结果只与上一行的结果有关,因此我们可以使用一位数组保存上一行结果 利用一层for循环不断更新
	int[] dp=new int[sum+1];
	for(int i=0;i<=sum;i++) {//第一行单独求出
		if(nums[0]<=i) {
			dp[i]=nums[0];
		}
	}
	for(int i=1;i<len;i++) {
		for(int j=sum;j>=1;j--) {  //注意 这里如果从前往后的话,会覆盖上一行dp,而后面求出的dp和前面dp相关,导致求出错误dp
			if(j>=nums[i]) {		//如果从后往前,那么求出的dp不会影响前面的dp
				dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
			}
		}
	}
	if(dp[sum]==sum) {
		return true;
	}
	return false;
}

猜你喜欢

转载自blog.csdn.net/qq_43073874/article/details/89737743