Bird
Raised Fist0
Interview PrepbacktrackingmediumAmazonGoogleMicrosoft

Permutations II (With Duplicates)

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Initialize and Sort Input

The input array [1,1,2] is sorted to group duplicates together, resulting in [1,1,2]. This sorting is essential for the skip condition to work correctly.

💡 Sorting groups duplicates so the algorithm can easily detect and skip repeated elements at each recursion level.
Line:nums.sort()
💡 Sorting is a prerequisite that enables efficient duplicate skipping during backtracking.
📊
Permutations II (With Duplicates) - Watch the Algorithm Execute, Step by Step
Watching this step-by-step execution reveals how sorting and skipping duplicates at each recursion level efficiently prune redundant branches, which is hard to grasp from code alone.
Step 1/15
·Active fillAnswer cell
enteringnums=[1,1,2]start=0
Call Path (current → root)
backtrack(start=0)
choosingnums=[1,1,2]start=0
Call Path (current → root)
backtrack(start=0)
Tried
i=0
Remaining
i=1i=2
Partial: [1]
choosingnums=[1,1,2]start=1
Call Path (current → root)
backtrack(start=1)
backtrack(start=0)
Remaining
i=1i=2
Partial: [1]
choosingnums=[1,1,2]start=2
Call Path (current → root)
backtrack(start=2)
backtrack(start=1)
backtrack(start=0)
Remaining
i=2
Partial: [1, 1]
choosingnums=[1,1,2]start=2
Call Path (current → root)
backtrack(start=2)
backtrack(start=1)
backtrack(start=0)
Tried
i=2
Partial: [1, 1, 2]
choosingnums=[1,1,2]start=2
Call Path (current → root)
backtrack(start=2)
backtrack(start=1)
backtrack(start=0)
Tried
i=2
Partial: [1, 1]
Found 1: [1,1,2]
choosingnums=[1,2,1]start=1
Call Path (current → root)
backtrack(start=1)
backtrack(start=0)
Tried
i=1i=2
Partial: [1, 2]
Found 1: [1,1,2]
choosingnums=[1,2,1]start=2
Call Path (current → root)
backtrack(start=2)
backtrack(start=1)
backtrack(start=0)
Tried
i=2
Partial: [1, 2, 1]
Found 1: [1,1,2]
choosingnums=[1,2,1]start=2
Call Path (current → root)
backtrack(start=2)
backtrack(start=1)
backtrack(start=0)
Tried
i=2
Partial: [1, 2]
Found 2: [1,1,2] [1,2,1]
choosingnums=[1,1,2]start=0
Call Path (current → root)
backtrack(start=0)
Tried
i=0
Remaining
i=2
nums[1]=1 already fixed at this level
Found 2: [1,1,2] [1,2,1]
enteringnums=[2,1,1]start=1
Call Path (current → root)
backtrack(start=1)
backtrack(start=0)
Tried
i=0i=2
Partial: [2]
Found 2: [1,1,2] [1,2,1]
choosingnums=[2,1,1]start=1
Call Path (current → root)
backtrack(start=1)
backtrack(start=0)
Tried
i=1
Remaining
i=2
Partial: [2, 1]
Found 2: [1,1,2] [1,2,1]
choosingnums=[2,1,1]start=2
Call Path (current → root)
backtrack(start=2)
backtrack(start=1)
backtrack(start=0)
Tried
i=2
Partial: [2, 1, 1]
Found 2: [1,1,2] [1,2,1]
backtrackingnums=[2,1,1]start=1
Call Path (current → root)
backtrack(start=0)
Tried
i=0i=2
Found 3: [1,2,1] [2,1,1]
backtrackingnums=[1,1,2]start=0
Call Path (current → root)
root call
Tried
i=0i=2
Found 3: [1,2,1] [2,1,1]

Key Takeaways

Sorting the input array is crucial to group duplicates and enable efficient skipping of repeated elements at each recursion level.

Without sorting, detecting duplicates to prune branches would be much harder and less efficient.

The 'seen' set at each recursion level tracks which elements have been fixed at that position, preventing duplicate permutations by skipping repeated elements.

This local duplicate tracking is the key insight that avoids generating redundant permutations.

Backtracking with swapping and undoing swaps restores the array state after exploring each branch, allowing the algorithm to systematically explore all unique permutations.

Understanding how backtracking restores state is essential to grasp how the recursion tree is fully explored without side effects.

Practice

(1/5)
1. You are given a string containing only digits. Your task is to split it into exactly four parts such that each part represents a valid IP address segment (0 to 255, no leading zeros except for '0'). Which algorithmic approach guarantees finding all valid IP addresses efficiently?
easy
A. Sorting the digits and then partitioning into four segments
B. Greedy approach that picks the shortest valid segment at each step
C. Dynamic programming to count the number of valid segmentations
D. Backtracking with pruning to explore all valid segmentations

Solution

  1. Step 1: Understand the problem constraints

    The problem requires enumerating all valid IP addresses, which involves exploring multiple segmentations of the string.
  2. Step 2: Evaluate algorithm suitability

    Greedy approaches fail because they may miss valid segmentations; DP counting does not generate all solutions; sorting digits destroys original order. Backtracking with pruning systematically explores all valid partitions.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Backtracking explores all partitions with pruning to avoid invalid segments [OK]
Hint: Backtracking explores all segmentations with pruning [OK]
Common Mistakes:
  • Assuming greedy can find all valid IPs
  • Using DP counting without generating solutions
2. What is the time complexity of the optimal backtracking solution for the Expression Add Operators problem, where n is the length of the input string? Assume the solution tries all operator insertions and substring splits with pruning and efficient string building.
medium
A. O(4^n) because at each position there are up to 4 choices (3 operators + no operator split)
B. O(n * 3^n) because each digit can be combined with 3 operators and substring splits
C. O(2^n) since only two operators are considered at each step
D. O(n^3) due to substring parsing and operator insertions

Solution

  1. Step 1: Identify branching factor per digit

    At each digit, we can insert one of 3 operators (+, -, *) or choose to extend the current operand (no operator), but the main branching factor is 3 operators per split, and substring splits add a factor of n.
  2. Step 2: Calculate total complexity

    The total complexity is roughly O(n * 3^n) because for each of the n positions, there are up to 3 operator choices, and substring splits add an n factor.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Exponential branching with 3 operators and substring splits [OK]
Hint: 3 operators per digit and substring splits lead to O(n * 3^n) complexity [OK]
Common Mistakes:
  • Confusing substring parsing cost as cubic
  • Assuming only 2 operators reduce complexity
  • Miscounting branching factor as 4
3. Examine the following buggy code snippet for Expression Add Operators. Which line contains the subtle bug that causes incorrect results on inputs with leading zeros?
def addOperators(num: str, target: int) -> List[str]:
    res = []
    path = []
    def backtrack(index: int, evaluated: int, last_operand: int):
        if index == len(num):
            if evaluated == target:
                res.append(''.join(path))
            return
        for i in range(index, len(num)):
            # Bug: missing leading zero check
            curr_str = num[index:i+1]
            curr = int(curr_str)
            length_before = len(path)
            if index == 0:
                path.append(curr_str)
                backtrack(i+1, curr, curr)
                path[length_before:] = []
            else:
                path.append('+'); path.append(curr_str)
                backtrack(i+1, evaluated + curr, curr)
                path[length_before:] = []
    backtrack(0, 0, 0)
    return res
medium
A. Line with 'if i != index and num[index] == '0':' missing here
B. Line with 'curr_str = num[index:i+1]' (substring extraction)
C. Line with 'path[length_before:] = []' (backtracking cleanup)
D. Line with 'path.append('+'); path.append(curr_str)' (operator insertion)

Solution

  1. Step 1: Identify handling of leading zeros

    The code lacks the check 'if i != index and num[index] == '0': break' which prevents invalid operands like "05".
  2. Step 2: Confirm bug location

    This missing check is critical and should be placed before parsing curr_str to avoid invalid expressions.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Missing leading zero check causes invalid operands [OK]
Hint: Leading zero check missing causes invalid operands [OK]
Common Mistakes:
  • Confusing backtracking cleanup lines as bug
  • Thinking substring extraction is buggy
4. What is the time complexity of the optimal in-place next permutation algorithm for an input array of length n?
medium
A. O(n) because it scans the array a constant number of times
B. O(n log n) because it sorts the suffix after the pivot
C. O(n!) due to generating all permutations
D. O(n^2) because it swaps elements multiple times in nested loops

Solution

  1. Step 1: Identify the main operations

    The algorithm scans from the end to find the pivot (O(n)), then scans again to find the swap element (O(n)), and finally reverses the suffix (O(n)).
  2. Step 2: Sum up the operations

    All steps are linear scans or swaps, so total time complexity is O(n).
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    No sorting or factorial generation involved, linear scans only [OK]
Hint: Next permutation scans array linearly multiple times [OK]
Common Mistakes:
  • Confusing suffix reversal with sorting
  • Assuming factorial due to permutations
5. What is the time complexity of the optimal backtracking with Trie approach for Word Search II, given a board of size MxN and a list of words with maximum length L? Assume the Trie is already built.
medium
A. O(M * N * 4 * 3^(L-1)) due to pruning and adjacency constraints
B. O(M * N * 4^L * W), where W is the number of words
C. O(M * N * L^2) because each cell explores all prefixes
D. O(M * N * L) since each cell is visited once per character

Solution

  1. Step 1: Identify branching factor in backtracking

    From each cell, up to 4 directions are possible initially, then up to 3 directions for subsequent steps due to no revisiting.
  2. Step 2: Calculate complexity with pruning

    Trie pruning reduces unnecessary paths, so complexity is roughly O(M * N * 4 * 3^(L-1)) where L is max word length.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Matches known complexity from Trie + backtracking analysis [OK]
Hint: Branching factor reduces after first step due to visited constraints [OK]
Common Mistakes:
  • Confusing W (number of words) as multiplicative factor in optimal approach.