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:
- 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.
Idea 1. Subset sum
[1, 5, 11, 5]
containing 1: [1], sum {1}
containing 5: [5], [1, 5] sum {5, 6}
containing 11: [11], [1, 11], [5, 11], [1, 5, 11] {11, 12, 16, 17}
containing: 5: [5], [1, 5], [5, 5], [1, 5, 5], [11, 5], [1, 11, 5], [5, 11, 5], [1, 5, 11, 5], {5, 6, 10, 11, 16, 17, 21, 22}
Time complexity: O(2^n -1)
Space complexity: O(2^n -1)
1 class Solution { 2 public boolean canPartition(int[] nums) { 3 int totalSum = 0; 4 for(int num: nums) { 5 totalSum += num; 6 } 7 if(totalSum%2 != 0) { 8 return false; 9 } 10 11 List<List<Integer>> endSum = new ArrayList<>(); 12 for(int i = 0; i < nums.length; ++i) { 13 List<Integer> curr = new ArrayList<>(); 14 if(nums[i] == totalSum/2) { 15 return true; 16 } 17 curr.add(nums[i]); 18 for(int j = 0; j < i; ++j) { 19 for(int val: endSum.get(j)) { 20 int currSum = val + nums[i]; 21 if(currSum == totalSum/2) { 22 return true; 23 } 24 curr.add(currSum); 25 } 26 } 27 endSum.add(curr); 28 } 29 return false; 30 } 31 }
Idea 2: dynamic programming. Let dp[i][j] represents if the subset sum from num[0..i] could reach j,
dp[i][j] = dp[i-1][j] not picking nums[i],
dp[i-1][j-nums[i]] picking nums[i]
Note. to initialise dp[-1][0] = 0
Time complexity: O(n*target)
Space complexity: O(n*target)
1 class Solution { 2 private void backtrack(int[] nums, int i, boolean[][] dp, int target) { 3 if(i > nums.length) { 4 return; 5 } 6 7 for(int j = 1; j <= target; ++j) { 8 dp[i][j] = dp[i-1][j]; 9 if(j >= nums[i-1]) { 10 dp[i][j] = dp[i][j] || dp[i-1][j-nums[i-1]]; 11 } 12 } 13 backtrack(nums, i+1, dp, target); 14 } 15 16 public boolean canPartition(int[] nums) { 17 int totalSum = 0; 18 for(int num: nums) { 19 totalSum += num; 20 } 21 22 if(totalSum %2 != 0) { 23 return false; 24 } 25 int n = nums.length; 26 int target = totalSum/2; 27 boolean[][] dp = new boolean[n+1][target+1]; 28 for(int i = 0; i <= n; ++i) { 29 dp[i][0] = true; 30 } 31 32 backtrack(nums, 1, dp, target); 33 return dp[n][target]; 34 } 35 }
1 class Solution { 2 public boolean canPartition(int[] nums) { 3 int totalSum = 0; 4 for(int num: nums) { 5 totalSum += num; 6 } 7 8 if(totalSum %2 != 0) { 9 return false; 10 } 11 12 int target = totalSum/2; 13 int m = nums.length; 14 boolean[][] dp = new boolean[m+1][target+1]; 15 dp[0][0] = true; 16 17 for(int i = 1; i <= m; ++i) { 18 for(int j = 1; j <= target; ++j) { 19 dp[i][j] = dp[i-1][j]; 20 if(j >= nums[i-1]) { 21 dp[i][j] = dp[i][j] || dp[i-1][j-nums[i-1]]; 22 } 23 } 24 } 25 26 return dp[m][target]; 27 } 28 }
Idea 2. dynamic programming, 二维到一维的优化,注意在二维公式中sum的循环是从小到大(从左到右),但是是前一行,转换成一维,需要用到前边的状态,所以要从右向左
dp[j] = dp[j] || dp[j-nums[i]]
dp[0] = true
Time complexity: O(n*target)
Space complexity: O(target)
1 class Solution { 2 public boolean canPartition(int[] nums) { 3 int totalSum = 0; 4 5 for(int num: nums) { 6 totalSum += num; 7 } 8 9 if(totalSum % 2 != 0) { 10 return false; 11 } 12 13 int target = totalSum/2; 14 int n = nums.length; 15 boolean[] dp = new boolean[target+1]; 16 dp[0] = true; 17 18 for(int i = 0; i < n; ++i) { 19 for(int j = target; j >= nums[i]; --j) { 20 dp[j] = dp[j] || dp[j-nums[i]]; 21 } 22 } 23 24 return dp[target]; 25 } 26 }
浙公网安备 33010602011771号