Bird
Raised Fist0
Interview PrepbacktrackingmediumAmazonGoogleMicrosoft

Permutations II (With Duplicates)

Choose your preparation mode4 modes available
📋
Problem

Imagine you have a collection of colored beads, some colors repeating, and you want to find all unique ways to arrange them on a string without repeating the same pattern twice.

Given a collection of numbers that might contain duplicates, return all possible unique permutations in any order. Input: An array of integers nums. Output: A list of lists, where each list is a unique permutation of nums.

1 ≤ nums.length ≤ 8-10 ≤ nums[i] ≤ 10
Edge cases: All elements are the same → only one unique permutationArray with no duplicates → all permutations are uniqueEmpty array → returns an empty list or list with empty permutation
</>
IDE
def permuteUnique(nums: list[int]) -> list[list[int]]:public List<List<Integer>> permuteUnique(int[] nums)vector<vector<int>> permuteUnique(vector<int>& nums)function permuteUnique(nums)
def permuteUnique(nums):
    # Write your solution here
    pass
class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        // Write your solution here
        return new ArrayList<>();
    }
}
#include <vector>
using namespace std;

vector<vector<int>> permuteUnique(vector<int>& nums) {
    // Write your solution here
    return {};
}
function permuteUnique(nums) {
    // Write your solution here
}
0/9
Common Bugs to Avoid
Wrong: [[1,1,2],[1,1,2],[1,2,1],[2,1,1],[2,1,1]]Duplicates not skipped during backtracking, causing repeated permutations.✅ Sort input and skip nums[i] if nums[i] == nums[i-1] and used[i-1] is false during recursion.
Wrong: []Empty input returns empty list instead of list with empty permutation.✅ Return [[]] when input is empty to represent one empty permutation.
Wrong: [[5],[5],[5]]Single element input returns duplicates due to incorrect duplicate skipping or recursion.✅ Ensure base case returns single permutation [[nums[0]]] without duplicates.
Wrong: [[2,2,2,2],[2,2,2,2],[2,2,2,2]]All identical elements produce multiple duplicate permutations due to missing skip condition.✅ Skip duplicates by checking if nums[i] == nums[i-1] and used[i-1] is false.
Wrong: [[1,2,2,3],[1,2,3,2],[1,3,2,2]]Greedy approach misses permutations by not exploring all branches.✅ Use full backtracking with used array and duplicate skipping to generate all permutations.
✓
Test Cases
t1_01basic
Input{"nums":[1,1,2]}
Expected[[1,1,2],[1,2,1],[2,1,1]]

The input has duplicates (two 1s). The output lists all unique permutations without repetition.

t1_02basic
Input{"nums":[1,2,3]}
Expected[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

All elements are unique, so all permutations are unique and included.

t2_01edge
Input{"nums":[]}
Expected[[]]

Empty input returns a list containing an empty permutation.

t2_02edge
Input{"nums":[5]}
Expected[[5]]

Single element array returns one permutation containing that element.

t2_03edge
Input{"nums":[2,2,2,2]}
Expected[[2,2,2,2]]

All elements identical, only one unique permutation exists.

t3_01corner
Input{"nums":[1,1,2,2]}
Expected[[1,1,2,2],[1,2,1,2],[1,2,2,1],[2,1,1,2],[2,1,2,1],[2,2,1,1]]

Duplicates of two different numbers require careful skipping to avoid duplicate permutations.

t3_02corner
Input{"nums":[-1,-1,2]}
Expected[[-1,-1,2],[-1,2,-1],[2,-1,-1]]

Negative duplicates test correct handling of negative numbers and duplicates.

t3_03corner
Input{"nums":[1,2,2,3]}
Expected[[1,2,2,3],[1,2,3,2],[1,3,2,2],[2,1,2,3],[2,1,3,2],[2,2,1,3],[2,2,3,1],[2,3,1,2],[2,3,2,1],[3,1,2,2],[3,2,1,2],[3,2,2,1]]

Tests that greedy approach picking first available element fails to generate all unique permutations.

t4_01performance
Input{"nums":[1,2,3,4,5,6,7,8]}
⏱ Performance - must finish in 2000ms

Maximum input size n=8 with all unique elements; O(n! * n) complexity must complete within 2 seconds.

Practice

(1/5)
1. Given the following code snippet for getPermutation, what is the returned value when calling getPermutation(3, 3)?
easy
A. '123'
B. '312'
C. '213'
D. '231'

Solution

  1. Step 1: Trace factorial array computation

    factorial = [1, 1, 2] for n=3.
  2. Step 2: Calculate indices and build result

    k=3 -> k=2 zero-based. For i=2: idx=2//2=1, pick '2'. For i=1: k=2%2=0, idx=0//1=0, pick '1'. For i=0: k=0%1=0, idx=0//1=0, pick '3'. Result = '213'.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Output matches expected k-th permutation '213' [OK]
Hint: Remember to convert k to zero-based before indexing [OK]
Common Mistakes:
  • Off-by-one error in k adjustment
  • Wrong index calculation in loop
  • Not popping used numbers
2. Consider the following BFS-based code snippet for removing invalid parentheses:
from collections import deque

def is_valid(s: str) -> bool:
    count = 0
    for c in s:
        if c == '(': count += 1
        elif c == ')':
            count -= 1
            if count < 0:
                return False
    return count == 0

def remove_invalid_parentheses_bfs(s: str):
    res = []
    visited = set([s])
    queue = deque([s])
    found = False

    while queue:
        size = len(queue)
        for _ in range(size):
            curr = queue.popleft()
            if is_valid(curr):
                res.append(curr)
                found = True
            if found:
                continue
            for i in range(len(curr)):
                if curr[i] not in ('(', ')'):
                    continue
                next_str = curr[:i] + curr[i+1:]
                if next_str not in visited:
                    visited.add(next_str)
                    queue.append(next_str)
    return res

print(remove_invalid_parentheses_bfs("()())()"))
What is the output of this code?
easy
A. ["()()()"]
B. ["()()()", "(())()"]
C. ["(())()"]
D. ["()())()"]

Solution

  1. Step 1: Trace BFS levels for input "()())()"

    Initial string is invalid. BFS removes one parenthesis at each position generating candidates. The first valid strings found are "()()()" and "(())()".
  2. Step 2: Confirm both valid strings are collected

    Since BFS stops adding new states after finding valid strings at current level, both minimal removal results are returned.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Both minimal valid strings are returned [OK]
Hint: BFS returns all minimal valid strings at first valid level [OK]
Common Mistakes:
  • Returning only one valid string
  • Returning original invalid string
  • Missing one minimal valid string
3. Consider the following code snippet for palindrome partitioning. Which line contains a subtle bug that causes incorrect or duplicate partitions?
def partition(s):
    def is_palindrome(left, right):
        while left < right:
            if s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True

    def backtrack(start, path):
        if start == len(s):
            result.append(path)  # Line X
            return
        for end in range(start, len(s)):
            if is_palindrome(start, end):
                path.append(s[start:end+1])
                backtrack(end+1, path)
                path.pop()

    result = []
    backtrack(0, [])
    return result
medium
A. Line 6: palindrome check misses single character substrings
B. Line X: appending path without copying causes shared references
C. Line 12: for loop range should be from start+1 to len(s)+1
D. Line 15: missing path.pop() after backtrack call

Solution

  1. Step 1: Identify how results are stored

    Appending path directly stores a reference, so later modifications affect all stored results.
  2. Step 2: Correct approach

    Use result.append(path[:]) to append a copy, preserving each partition snapshot.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Shared references cause incorrect final partitions [OK]
Hint: Always append a copy of path to results [OK]
Common Mistakes:
  • Forgetting to copy path before appending
  • Incorrect palindrome check boundaries
  • Forgetting to pop after recursion
4. Identify the bug in the following code snippet for getPermutation:
medium
A. Line 6: k is not converted to zero-based index before calculations.
B. Line 2: factorial array initialization is incorrect.
C. Line 10: The index calculation uses integer division incorrectly.
D. Line 12: numbers.pop(idx) should be numbers.remove(idx).

Solution

  1. Step 1: Check k adjustment

    k must be decremented by 1 to convert to zero-based indexing before using factorial divisions.
  2. Step 2: Understand impact of missing k -= 1

    Without this, idx calculation is off by one, leading to incorrect permutation output.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Missing k -= 1 causes wrong indexing and wrong permutation [OK]
Hint: Always convert k to zero-based before factorial indexing [OK]
Common Mistakes:
  • Forgetting zero-based index adjustment
  • Misusing pop vs remove
  • Incorrect factorial initialization
5. Suppose the problem is modified so that parentheses can be reused multiple times (e.g., you can insert removed parentheses back anywhere). Which of the following algorithmic changes correctly adapts the BFS approach to handle this variant?
hard
A. Switch to backtracking with memoization to explore insertions and removals explicitly, pruning invalid states
B. Use BFS as is, since it already explores all possible removals and insertions implicitly
C. Use a greedy approach to insert parentheses at earliest invalid positions without BFS or backtracking
D. Modify BFS to allow adding parentheses back by generating new states with insertions at every position

Solution

  1. Step 1: Understand reuse of parentheses

    Allowing reuse means we can insert parentheses anywhere, greatly increasing state space and complexity.
  2. Step 2: Analyze BFS suitability

    Standard BFS only removes characters; it does not handle insertions, so it cannot explore all states correctly.
  3. Step 3: Identify correct approach

    Backtracking with memoization can explicitly explore insertions and removals, pruning invalid states to handle reuse properly.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Backtracking with memoization handles insertions and pruning [OK]
Hint: Reuse requires explicit insertion exploration, not just removal BFS [OK]
Common Mistakes:
  • Assuming BFS handles insertions
  • Using greedy for complex insertions
  • Modifying BFS without pruning leads to explosion
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard