Two approaches to LeetCode Subsets II β generate-all + deduplicate and optimal backtracking with sort-and-skip duplicates. Java and Python solutions with walkthrough.
LeetCode Β· #90
Subsets II Solution
Given an integer array nums that may contain duplicates, return all possible subsets without duplicate subsets.
This is the duplicate-aware version of Subsets. We still want the full power set, but repeated values in the input must not produce repeated subsets in the output.
Generate every subset as if all values were unique, but normalize each subset and store it in a set so duplicates collapse into one entry.
Problem: This works, but it spends time generating duplicate subsets first and only removes them afterward. We can avoid creating duplicates at all by sorting and skipping repeated values at the same recursion depth.
Java β Deduplicate with a set
import java.util.*;
classSolution {
publicList<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
Set<List<Integer>> set = newLinkedHashSet<>();
dfs(nums, 0, newArrayList<>(), set);
returnnewArrayList<>(set);
}
privatevoiddfs(int[] nums, int i,
List<Integer> path,
Set<List<Integer>> set) {
if (i == nums.length) {
set.add(newArrayList<>(path));
return;
}
path.add(nums[i]);
dfs(nums, i + 1, path, set);
path.remove(path.size() - 1);
dfs(nums, i + 1, path, set);
}
}
Python β Deduplicate with a set
classSolution:
defsubsetsWithDup(self, nums: list[int]) -> list[list[int]]:
nums.sort()
seen = set()
defdfs(i: int, path: list[int]) -> None:
if i == len(nums):
seen.add(tuple(path))
return
path.append(nums[i])
dfs(i + 1, path)
path.pop()
dfs(i + 1, path)
dfs(0, [])
return [list(t) for t in seen]
Metric
Value
Time
O(n Β· 2βΏ)
Space
O(n Β· 2βΏ)
03
Section Three Β· Approach 2
Backtracking with Sort + Skip
Sort the array first. Then, while exploring choices from left to right, skip a value if it equals the previous one and both are being considered at the same recursion depth. This prevents duplicate subsets from ever being generated.
π‘ Mental model: Imagine identical books on a shelf. At one decision level, taking the first copy of book β2β or the second copy as the starting pick creates the same subset shape. So at that same shelf level, you pick only the first identical copy and skip the rest. Deeper recursion is different, because choosing the second copy after already choosing the first gives subsets like [2,2], which are valid and distinct.
Algorithm
Sort nums so duplicates sit next to each other.
Add the current path to the answer at every node.
Loop from start onward.
If i > start && nums[i] == nums[i-1], skip it β same value at same level.
Recurse with i + 1 because subsets do not reuse indices.
π― Key invariant:i > start means βsame recursion level.β That condition is what prevents duplicates without blocking valid deeper subsets like [2,2].
04
Section Four Β· Trace
Visual Walkthrough
Trace for nums = [1,2,2] after sorting:
Skip duplicate 2 only at the same level
05
Section Five Β· Implementation
Code β Java & Python
Java β Sort + skip duplicates
import java.util.*;
classSolution {
publicList<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = newArrayList<>();
backtrack(nums, 0, newArrayList<>(), res);
return res;
}
privatevoidbacktrack(int[] nums, int start,
List<Integer> path,
List<List<Integer>> res) {
res.add(newArrayList<>(path));
for (int i = start; i < nums.length; i++) {
if (i > start && nums[i] == nums[i - 1]) continue;
path.add(nums[i]);
backtrack(nums, i + 1, path, res);
path.remove(path.size() - 1);
}
}
}
Python β Sort + skip duplicates
classSolution:
defsubsetsWithDup(self, nums: list[int]) -> list[list[int]]:
nums.sort()
res = []
defbacktrack(start: int, path: list[int]) -> None:
res.append(path[:])
for i in range(start, len(nums)):
if i > start and nums[i] == nums[i - 1]:
continue
path.append(nums[i])
backtrack(i + 1, path)
path.pop()
backtrack(0, [])
return res
06
Section Six Β· Analysis
Complexity Analysis
Approach
Time
Space
Trade-off
Generate-all + set
O(n Β· 2βΏ)
O(n Β· 2βΏ)
Simple but creates duplicates first
Sort + skip β optimal
O(n Β· 2βΏ)
O(n Β· 2βΏ)
Avoids duplicate branches entirely
07
Section Seven Β· Edge Cases
Edge Cases & Pitfalls
Case
Input
Why It Matters
All same
[2,2,2]
Answer should be [], [2], [2,2], [2,2,2].
No duplicates
[1,2,3]
Behaves exactly like LC 78.
Single element
[0]
Only [] and [0].
Negative values
[-1,-1]
Sorting and dedup logic still works.
β Common Mistake: Writing if (nums[i] == nums[i-1]) continue; without checking i > start. That incorrectly skips valid deeper choices and loses subsets like [2,2].