↓Skip to main content
  1. LeetCode/

LeetCode 90: Subsets II

·2 mins· ·
LeetCode Medium Array Backtracking Bit-Manipulation
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: medium First Attempt: 2022-10-26

  • Submissions: Accepted ×2 → Runtime Error → Wrong Answer ×2 → Runtime Error ×3 → Wrong Answer → Accepted → Wrong Answer → Accepted → Wrong Answer ×2 → Accepted

Approach
#

Duplicates require deduplication (Backtracking Variation 4). Sort so equal values are adjacent. Iteratively, a new value extends every subset, but a value equal to the previous one extends only the subsets created in the previous step (those already contain the previous copy); anything else repeats an existing subset. With backtracking, skip equal choices within the same level: if i > start and nums[i] == nums[i - 1]: continue.

My Attempts
#

This took 15 submissions:

  • The first acceptance deduplicated with if c + [num] not in combs, scanning every subset on each check, which is slow.
  • Then I switched to “a repeated value extends only the subsets from the previous step”, and several times forgot to sort, so equal values were not adjacent: [1, 2, 1] returned [1] twice and [1, 2] twice.
  • The rest misused the variable recording how many subsets the previous step created or inverted the condition (updating only when nums[i] == nums[i - 1]); sorting and using != made it pass reliably.

Solution
#

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = []
        def dfs(start, path):
            res.append(path[:])
            for i in range(start, len(nums)):
                if i > start and nums[i] == nums[i - 1]:
                    continue
                path.append(nums[i])
                dfs(i + 1, path)
                path.pop()
        dfs(0, [])
        return res

Complexity
#

Time O(n · 2^n), space O(n) excluding output.

Mistakes to Avoid
#

  • Sort before deduplicating.
  • The skip condition is i > start (same level), not i > 0, or subsets like [1, 1] are lost.
  • Deduplicating with not in res costs O(2^n) per check and is slow.

Interview Explanation
#

I sort so equal values are adjacent and, while backtracking, skip a choice equal to the previous one at the same level, so each subset appears once. Time O(n · 2^n).

Related

LeetCode 78: Subsets
·1 min
LeetCode Medium Array Backtracking Bit-Manipulation
LeetCode 78 note: each element is either taken or not; iteratively, each new number copies every existing subset with the number appended
LeetCode 79: Word Search
·3 mins
LeetCode Medium Array String Backtracking Depth-First-Search
LeetCode 79 note: backtrack from every cell, matching the next character in four directions with visited cells marked temporarily and restored; prune early with character counts
LeetCode 47: Permutations II
·2 mins
LeetCode Medium Array Backtracking Sorting
LeetCode 47 note: sort first, and within a level skip a value equal to the previous one when the previous one is unused
LeetCode 39: Combination Sum
·2 mins
LeetCode Medium Array Backtracking
LeetCode 39 note: numbers may be reused, so the next level starts at i (not i + 1), which also avoids duplicates differing only in order
LeetCode 40: Combination Sum II
·2 mins
LeetCode Medium Array Backtracking
LeetCode 40 note: each number is used once and duplicates exist, so sort, start the next level at i + 1, and skip equal values within a level
LeetCode 46: Permutations
·2 mins
LeetCode Medium Array Backtracking
LeetCode 46 note: each level picks one unused number, marked in a used array, and records when the path is full