Approach 1 (Proposed by Hickey)
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
List<Integer> path = new ArrayList<>();
backtrack(nums, 0, result, path);
return result;
}
private void backtrack(int[] nums, int level, List<List<Integer>> result, List<Integer> path) {
if (level == nums.length) {
result.add(new ArrayList<>(path));
return;
}
path.add(nums[level]);
backtrack(nums, level + 1, result, path);
path.remove(path.size() - 1);
// 一定要放在选之后,没选之前
while (level + 1 < nums.length && nums[level] == nums[level + 1]) {
level++;
}
backtrack(nums, level + 1, result, path);
}
}
https://www.laioffer.com/en/news/2017-06-02-multiple-ways-to-solve-subsets-ii/
Approach 2
需要注意的是 nums[i - 1] == nums[i] 的作用是在递归树的同一层上的, 也就是防止 nums = [1, 2, 2'] 出现 [1, 2], [1, 2'] 两个重复的解 (即: 通过 nums[1] == nums[2]: continue 进行的剪枝)
而解 [1, 2, 2'] 实际中的 2, 2' 是位于递归树的不同层级的, 也就是剪枝要从每一层的第二个元素开始, 所以还要增加一个 i > start 或者 i != start
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
backtrack(nums, 0, new ArrayList<>(), res);
return res;
}
private void backtrack(int[] nums, int smallestCandidate, List<Integer> path, List<List<Integer>> res){
res.add(new ArrayList<>(path));
for(int i = smallestCandidate; i < nums.length; i++){
if(i > smallestCandidate && nums[i] == nums[i - 1]){
continue;
}
path.add(nums[i]);
backtrack(nums, i + 1, path, res);
path.remove(path.size() - 1);
}
}
}
https://leetcode-cn.com/problems/subsets-ii/solution/jian-zhi-qu-zhong-de-si-lu-by-mrsate/