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:
Each of the array element will not exceed 100.
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.
题意是把一个数组分割成两部分,能否使两部分的值相等,这就跟背包问题差不多了,只是背包问题有价值重量,这里只有价值,比背包简单点,只要能背满就行,而背包问题需要求解最大值。利用递归求解的话就很简单了,划分下子问题,假设当前只有一个元素,如果剩下的元素如果能填满二分之一的重量则不加入,否则加入试试。
/*
* 没用备忘录法进行优化,因为这不是重点,这个方法只是提及一下
*
* /
public static int partition(int[] nums, int index, int sum) {
if (sum == 0)
return 1;
if (index < 0 || sum < 0)
return 0;
return (partition(nums, index - 1, sum) == 1 || partition(nums, index - 1, sum - nums[index]) == 1) ? 1 : 0;
}
public static boolean canPartition(int[] nums) {
if (nums.length <= 1)
return false;
int sum = 0;
for (int i = 0; i < nums.length; i++)
sum = sum + nums[i];
if (sum % 2 != 0)
return false;
return partition(nums, nums.length - 1, sum/2) == 1;
}
既然是背包问题变型,那么显而易见对背包的求解进行下改改可以直接得到解法,因为只要我们把背包定为二分之一数组和大小,查看下最大值是不是这个和就行了。
/*
* 动态规划法
*/
public static boolean canPartition(int[] nums) {
if (nums.length <= 1)
return false;
int sum = 0,N=nums.length;
for (int i = 0; i < N; i++)
sum = sum + nums[i];
if (sum % 2 != 0)
return false;
else
sum=sum/2;
int memo[][]=new int[N+1][sum+1];
for(int i=1;i<N;i++){
for(int j=1;j<=sum;j++){
if(nums[i]<=j){
memo[i][j]=max(memo[i-1][j],memo[i-1][j-nums[i]]+nums[i]);
}else{
memo[i][j]=memo[i-1][j];
}
}
}
return memo[N-1][sum]==sum;
}
当然,我们还有种更加省空间的做法
解法2
public static boolean canPartition(int[] nums) {
if (nums.length <= 1)
return false;
int sum = 0, N = nums.length;
for (int i = 0; i < N; i++)
sum = sum + nums[i];
if (sum % 2 != 0)
return false;
else
sum = sum / 2;
boolean memo[] = new boolean[sum + 1];
memo[0] = true;
for (int j = 0; j <= sum; j++)
memo[j] = (nums[0] == j);
for (int i = 0; i < N; i++) {
for (int j = nums[i]; j <= sum; j++)
memo[j] = memo[j] || memo[j - nums[i]];
}
return memo[sum];
}