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.
思路:动态规划
- 如果能等分,则该数组的和必须为2的倍数
- 如果能被2整除,则该问题变成0-1背包问题,对于第i个数字,我们花费v的价格可以得到价值为dp[i][v],其状态转移方程为
d p ( i , j ) = M a t h . m a x ( d p ( i − 1 , j ) , d p ( i − 1 , j − n u m s [ i ] ) ) + n u m s [ i ] ) \color{red}{dp(i,j)=Math.max(dp(i-1,j),dp(i-1,j-nums[i]))+nums[i])} dp(i,j)=Math.max(dp(i−1,j),dp(i−1,j−nums[i]))+nums[i]) - 我们可以将以上二维数组优化为一维数组
d p ( i ) = M a t h . m a x ( d p ( i ) , d p ( i − n u m s [ i ] ) + n u m s [ i ] ) \color{red}{dp(i)=Math.max(dp(i),dp(i-nums[i])+nums[i])} dp(i)=Math.max(dp(i),dp(i−nums[i])+nums[i])
public boolean canPartition(int[] nums) {
int sum = 0;
for (int n : nums) {
sum += n;
}
if (sum % 2 == 1) return false;
sum = sum / 2;
int N = nums.length;
int[] dp = new int[sum+1];
for (int i = 0; i < N; i++) {
for (int j = sum; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
return dp[sum]==sum;
}
之后看到一个很有意思的解法
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for(int i : nums) {
sum+=i;
}
if(sum % 2 != 0)
return false;
return helper(nums, nums.length-1, sum/2);
}
private boolean helper(int[] nums, int i, int sum) {
if(sum == 0) {
return true;
}
else if(i < 0 || sum < 0 || sum < nums[i]) {
return false;
}
else {
return helper(nums, i - 1, sum - nums[i]) || helper(nums, i - 1, sum);
}
}
}