Subsets II
Sort, then skip a duplicate value among siblings
The plain Subsets recursion builds each subset by choosing a next index from start onward, so no subset is ever built in two different orders. Duplicates therefore arise from just one place: two equal VALUES at different indices offered as alternatives at the same depth. Sort the array so equal values are adjacent, then inside the loop refuse nums[i] when it equals nums[i - 1] and i > start. The i > start part is the subtle half — the same value one level deeper (chosen right after its twin) is a genuinely new subset, and the guard must let it through. The cells row is the sorted input: tinted cells are the current path, and a red cell is a duplicate being skipped.
Details
Animated on: nums = [1, 2, 2] contains a duplicate. Return every subset exactly once. Answer: [] [1] [1, 2] [1, 2, 2] [2] [2, 2].
Problem:Subsets IIMedium
Pattern:Backtracking Basics
Sort, then skip a duplicate value among siblings
step 1 / 10
Sort first: nums <- [1, 2, 2]. Equal values are now neighbours, so "is this the same value as the one I just tried at this depth?" becomes a single comparison with nums[i - 1]. Without sorting, the duplicates could sit anywhere and picking them in a different order would still build the same subset twice.
1FUNCTION subsetsWithDup(nums)2 SORT nums3 out <- EMPTY LIST, path <- EMPTY LIST4 FUNCTION backtrack(start)5 APPEND COPY(path) TO out6 FOR i <- start TO LENGTH(nums) - 17 IF i > start AND nums[i] = nums[i - 1]8 CONTINUE9 APPEND nums[i] TO path10 backtrack(i + 1)11 REMOVE LAST FROM path12 backtrack(0)13 RETURN out
← / → step · space play · Home restart
Every step in words
Show all 10 steps
- Sort first: nums <- [1, 2, 2]. Equal values are now neighbours, so "is this the same value as the one I just tried at this depth?" becomes a single comparison with nums[i - 1]. Without sorting, the duplicates could sit anywhere and picking them in a different order would still build the same subset twice.
- Every path is a subset, so record [] the moment this call begins — there is no "leaf" test. 1 subset so far. Next choices come from index 0 onward, never earlier, so each subset is built in one fixed order.
- Every path is a subset, so record [1] the moment this call begins — there is no "leaf" test. 2 subsets so far. Next choices come from index 1 onward, never earlier, so each subset is built in one fixed order.
- Every path is a subset, so record [1, 2] the moment this call begins — there is no "leaf" test. 3 subsets so far. Next choices come from index 2 onward, never earlier, so each subset is built in one fixed order.
- Every path is a subset, so record [1, 2, 2] the moment this call begins — there is no "leaf" test. 4 subsets so far. Next choices come from index 3 onward, never earlier, so each subset is built in one fixed order.
- Skip: nums[2]=2 equals nums[1]=2, and i=2 > start=1 means this is a SIBLING choice at the same depth — the 2 branch already produced every subset that begins [1, 2]. Taking it again would duplicate them. Note the guard needs i > start: a duplicate one level DEEPER is legal, which is how [1, 2, 2] still gets built.
- Every path is a subset, so record [2] the moment this call begins — there is no "leaf" test. 5 subsets so far. Next choices come from index 2 onward, never earlier, so each subset is built in one fixed order.
- Every path is a subset, so record [2, 2] the moment this call begins — there is no "leaf" test. 6 subsets so far. Next choices come from index 3 onward, never earlier, so each subset is built in one fixed order.
- Skip: nums[2]=2 equals nums[1]=2, and i=2 > start=0 means this is a SIBLING choice at the same depth — the 2 branch already produced every subset that begins [2]. Taking it again would duplicate them. Note the guard needs i > start: a duplicate one level DEEPER is legal, which is how [2, 2] still gets built.
- Loop exhausted at every level, so the recursion unwinds to the top. 6 unique subsets: [] [1] [1, 2] [1, 2, 2] [2] [2, 2]. The plain power set of 3 elements has 8; the 2 skipped sibling branches would have rebuilt [1, 2] and [2] a second time.
Now solve it yourself
Watching is the first half. The second is writing it without the animation.