◀ THE GRIND — BACKTRACKING

Permutations II

MEDIUM✓ CHIP-TIMEDLC #47 — FULL STATEMENT ↗

The drill: Same as ordering a list every possible way, except values can repeat — return every distinct ordering exactly once, even though swapping two equal values produces a sequence that looks identical.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

A list of numbers that may repeat arrives, and the task mirrors plain permutations: produce every ordering that uses each element exactly once.

Because values can repeat, swapping two equal numbers into each other's positions produces an ordering that looks exactly the same as the one it replaced — that duplicate must not appear twice in the output.

Two orderings are considered the same result only when the sequence of values matches position for position, ignoring which physical element supplied which value.

EX 01
nums = [1, 1]
[[1, 1]]
IDENTICAL PAIR COLLAPSES TO ONE ORDERING
EX 02
nums = [1, 2]
[[1, 2], [2, 1]]
NO DUPLICATES, CONTROL CASE
EX 03
nums = [1, 1, 2]
[[1, 1, 2], [1, 2, 1], [2, 1, 1]]
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

Treating every position as a distinct slot still works for counting arrangements, but two orderings that differ only by swapping equal values are the same output — that collision has to be prevented, not cleaned up after.

HINT 2 THE STRUCTURE

Sort the values first. At a given position, using a repeated value as anything but the FIRST fill for that position — among the values still available — just reproduces an ordering already built.

HINT 3 ONE STEP FROM THE ANSWER

Track which indices are used. At each position, skip index i when nums[i] equals nums[i − 1] and index i − 1 is currently unused — that's exactly the signal that this branch would only repeat work.

COACH'S BOARD — THE PATTERN, STEP BY STEP
THE FREE-TWIN SKIPPATTERN · SORTED BACKTRACK, SKIP FREE TWINSnums = [1, 1, 2]
STEP 1

Three numbers, one duplicate pair: 1, 1, 2. Sorting groups the duplicates so a used-tracking rule can skip repeat orderings.

STEP 1 / 10 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/permutations-ii.pyRACE PACE
LANG ▸
PACE ▸
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        used = [False] * n
        path = []
        res = []

        def backtrack():
            if len(path) == n:
                res.append(list(path))
                return
            for i in range(n):
                if used[i]:
                    continue
                if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
                    continue  # predecessor twin still free — this branch repeats work
                used[i] = True
                path.append(nums[i])
                backtrack()
                path.pop()
                used[i] = False

        backtrack()
        return res
TIME O(N·N!)SPACE O(N)PYTHON · RACE PACE · 25 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED