90. Subsets Ii
class Solution:
"""🎲 Subsets II.
Problem:
--------
Given an integer array `nums` that may contain duplicates, return all possible subsets
(the power set), in any order. The solution set must not contain duplicate subsets.
Approach:
---------
Backtracking as in Subsets (78): each node extends the candidate with an element after
the last one picked, so every node of the tree is a distinct subset. Duplicates are
pruned by sorting `nums` first, so equal values sit next to each other, and then picking
only the first of a run of equal values at each position: skip `nums[idx]` when
`idx > start_idx` and it equals `nums[idx - 1]`. A later copy at the same position would
rebuild the subsets the first copy already produced.
- Complete: every call is a valid subset, so record a copy on entry.
- Make move: append `nums[idx]`, then recurse from `idx + 1`.
- Unmake move: pop it.
Complexity:
-----------
- Time: O(n * 2^n), at most 2^n subsets (all values distinct), each copied in O(n).
The O(n log n) sort is dominated.
- Space: O(n) auxiliary for the candidate and the recursion stack;
O(n * 2^n) for the output.
"""
def subsetsWithDup(self, nums: list[int]) -> list[list[int]]:
results: list[list[int]] = []
candidate: list[int] = []
nums.sort()
def backtrack(start_idx: int) -> None:
results.append(candidate[:])
for idx in range(start_idx, len(nums)):
if idx > start_idx and nums[idx] == nums[idx - 1]:
continue
candidate.append(nums[idx])
backtrack(idx + 1)
candidate.pop()
backtrack(0)
return results