Same shape as Subsets, but duplicate values in the input can otherwise produce duplicate subsets in the output (e.g. picking βthe first 2β vs. βthe second 2β from [2,2] both look like [2]).
Brute Force: Bitmask + Set Dedup
Time O(n Β· 2^n)Space O(n Β· 2^n)Enumerate all 2^n bitmasks exactly as in Subsets, but since duplicate values now generate duplicate subsets, sort each candidate subset and only keep it if it hasnβt been seen before.
class Solution: def subsetsWithDup(self, nums: list[int]) -> list[list[int]]: n = len(nums) seen = set() result = [] for mask in range(1 << n): subset = tuple(sorted(nums[i] for i in range(n) if mask & (1 << i))) if subset not in seen: seen.add(subset) result.append(list(subset)) return resultStill visits all 2^n masks even though many collapse to the same subset once sorted β the dedup happens after the fact instead of being avoided.
Sort + Skip Adjacent Duplicates at Each Depth
OptimalTime O(n Β· 2^n)Space O(n)Sort nums so equal values are adjacent, then reuse the Subsets backtracking template with one added rule: within a single callβs loop, skip a value if it equals the previous value at the same depth (i > start). The first occurrence of a repeated value is always explored fully; only its later duplicates at that same decision point are skipped, since they would just re-derive subsets already produced by the first occurrence.
class Solution: def subsetsWithDup(self, nums: list[int]) -> list[list[int]]: nums.sort() result = [] path = []
def backtrack(start): result.append(path[:]) for i in range(start, len(nums)): if i > start and nums[i] == nums[i - 1]: continue # duplicate value at this depth, already covered path.append(nums[i]) backtrack(i + 1) path.pop()
backtrack(0) return resultTracing nums = [1,2,2] (already sorted): the root records [], then explores 1 before 2. Inside the 1-branch we may still use both copies of 2 (they are at increasing depths, not siblings), but back at the root, the second top-level 2 is skipped as a sibling duplicate of the first:
backtrack(0)β record[]; loopi=0(1) β path[1], record itbacktrack(1)β loopi=1(2) β path[1,2], record itbacktrack(2)β loopi=2(2) β path[1,2,2], record it
- loop continues at
i=2:nums[2]==nums[1]buti==start(1)is false only ifi>start; herestart=1, soi=2>1andnums[2]==nums[1]β skip
- back at root, loop
i=1(2) β path[2], record itbacktrack(2)β path[2,2], record it
- loop continues at
i=2:i=2 > start(0)andnums[2]==nums[1]β skip (this is the top-level duplicate that would have produced[2]again)
Result: [[], [1], [1,2], [1,2,2], [2], [2,2]] β exactly 6, matching 2^3 minus the 2 duplicate subsets that the skip rule prevented from ever being generated.
Complexity: worst case (all distinct values) still explores all 2^n subsets, each copied in O(n) β O(n Β· 2^n) time; recursion depth and path are O(n) β O(n) auxiliary space, with no post-hoc dedup structure needed.