Problem
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.
Solution
DFS1
class Solution {
public boolean canPartition(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
int sum = 0;
for (int num: nums) {
map.put(num, map.getOrDefault(num, 0)+1);
sum += num;
}
if (sum % 2 != 0) return false;
return dfs(map, sum/2);
}
private boolean dfs(Map<Integer, Integer> map, int target) {
if (map.containsKey(target) && map.get(target) > 0) return true;
for (int num: map.keySet()) {
if (num < target && map.get(num) > 0) {
map.put(num, map.get(num)-1);
if (dfs(map, target-num)) return true;
map.put(num, map.get(num)+1);
}
}
return false;
}
}
DFS2 – TLE
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int num: nums) sum += num;
if (sum%2 != 0) return false;
int target = sum/2;
return dfs(nums, new boolean[nums.length], 0, 0, target);
}
private boolean dfs(int[] nums, boolean[] used, int start, int sum, int target) {
if (sum > target || start >= nums.length) return false;
if (sum == target) return true;
for (int i = start; i < nums.length; i++) {
if (nums[i] > target) return false;
if (!used[i]) {
used[i] = true;
if (dfs(nums, used, i+1, sum+nums[i], target)) return true;
used[i] = false;
}
}
return false;
}
}
TLE for this test case:
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,100]