Overview
A permutation is an ordering of all elements. n distinct elements have n! permutations. Generating them uses backtracking: at each position, try every element not used yet, recurse to fill the next position, then undo.
Two implementations are common: a used[] boolean array with a path, or in-place swapping where you swap each candidate into the current position. With duplicate values, sort and skip a value if an identical earlier value has not been used yet, so identical orderings are not repeated.
For the first chair you have n choices, for the second n - 1 remaining guests, and so on. Trying every seating plan means filling chairs one by one and swapping guests back out to try alternatives.
When to use it
- All orderings or arrangements of items.
- n is small (n <= 8 to 10; 10! is about 3.6 million).
- The next lexicographic arrangement (next permutation) is needed.
- Permutations with constraints (beautiful arrangements, no adjacent equal letters).
Problem patterns it solves
Recognize it when: every ordering of distinct items.
- 46. Permutations
- 784. Letter Case Permutation
Recognize it when: repeated values; output must be unique.
- 47. Permutations II
- 1079. Letter Tile Possibilities
Recognize it when: compute one specific ordering without generating all.
- 31. Next Permutation
- 60. Permutation Sequence
- 556. Next Greater Element III
Recognize it when: orderings that satisfy position rules.
- 526. Beautiful Arrangement
- 996. Number of Squareful Arrays
- 267. Palindrome Permutation II
Where it is used in real software
Brute-force traveling salesman solutions try permutations of stops; real systems use heuristics because n! grows too fast.
Testing every order of operations to catch order-dependent bugs, for small numbers of steps.
Fisher-Yates shuffling produces uniformly random permutations for card games and randomized experiments.
Key terms
- n!
- Number of permutations of n distinct items.
- used[]
- Marks which elements are already in the current path.
- Swap-based permutation
- Place each candidate at position i by swapping, recurse on i + 1, swap back.
- Lexicographic order
- Dictionary order of sequences.
How it works, step by step
- 1Base case
When the path length equals n, record a copy.
- 2Try each unused element
Loop i from 0 to n - 1, skipping used[i].
- 3Skip duplicates
After sorting: if nums[i] === nums[i - 1] and !used[i - 1], skip.
- 4Choose, recurse, undo
used[i] = true; path.push; recurse; path.pop; used[i] = false.
Next permutation of [1, 3, 5, 4, 2]
Find the next larger ordering in lexicographic order, in place
| Step | Action | Array |
|---|---|---|
| 1 | From the right, find first i with a[i] < a[i + 1]: i = 1 (3 < 5) | [1, 3, 5, 4, 2] |
| 2 | From the right, find first j with a[j] > a[i]: j = 3 (4 > 3) | [1, 3, 5, 4, 2] |
| 3 | Swap a[i] and a[j] | [1, 4, 5, 3, 2] |
| 4 | Reverse the suffix after i | [1, 4, 2, 3, 5] |
NOWStep: 1 | Action: From the right, find first i with a[i] < a[i + 1]: i = 1 (3 < 5) | Array: [1, 3, 5, 4, 2]
The suffix after i was in decreasing order (its largest arrangement); swapping in the next larger value and reversing the suffix gives the smallest arrangement with the new prefix. O(n), no generation of all permutations.
Implementation
function permute(nums) { const result = [], path = []; const used = new Array(nums.length).fill(false); function backtrack() { if (path.length === nums.length) { result.push([...path]); return; } for (let i = 0; i < nums.length; i++) { if (used[i]) continue; used[i] = true; path.push(nums[i]); backtrack(); path.pop(); used[i] = false; } } backtrack(); return result;} // 47. Permutations IIfunction permuteUnique(nums) { nums.sort((a, b) => a - b); const result = [], path = []; const used = new Array(nums.length).fill(false); function backtrack() { if (path.length === nums.length) { result.push([...path]); return; } for (let i = 0; i < nums.length; i++) { if (used[i]) continue; if (i > 0 && nums[i] === nums[i - 1] && !used[i - 1]) continue; // use copies in order used[i] = true; path.push(nums[i]); backtrack(); path.pop(); used[i] = false; } } backtrack(); return result;} // 31. Next Permutationfunction nextPermutation(a) { let i = a.length - 2; while (i >= 0 && a[i] >= a[i + 1]) i--; if (i >= 0) { let j = a.length - 1; while (a[j] <= a[i]) j--; [a[i], a[j]] = [a[j], a[i]]; } for (let l = i + 1, r = a.length - 1; l < r; l++, r--) [a[l], a[r]] = [a[r], a[l]];}Complexity and performance
n! results, O(n) to copy each.
In place, O(1) extra space.
Factorial number system; list removals.
Recursion and used array.
Trade-offs
used[] keeps output in lexicographic order for sorted input and makes duplicate handling easy. Swapping uses less memory but does not keep order.
For next or kth permutation, direct formulas avoid generating n! results.
Variants and related techniques
Generates each permutation from the previous by a single swap.
Uniform random permutation in O(n): swap a[i] with a random j <= i from the end.
Bitmask DP over used elements when you only need a count.
Common mistakes
- Wrong duplicate rule.
Fix: Skip when nums[i] === nums[i - 1] and !used[i - 1]; this forces identical values to be used in index order.
- Forgetting to reverse the suffix in next permutation.
Fix: After the swap, the suffix is still descending and must be reversed.
- Running full generation for large n.
Fix: n = 12 is already about 479 million permutations; look for a formula or DP.
Interview questions
How do you avoid duplicate permutations?
Sort the array. Only use a duplicate value if its previous identical copy is already used in the current path. This fixes the relative order of identical values, removing repeated orderings.
Explain next permutation.
Find the rightmost position where the sequence increases, swap that element with the smallest larger element to its right, then reverse the suffix to make it as small as possible.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 46. Permutations | Medium | Core backtracking. |
| 47. Permutations II | Medium | Duplicate rule. |
| 31. Next Permutation | Medium | In-place algorithm. |
| 526. Beautiful Arrangement | Medium | Pruning by position. |
| 60. Permutation Sequence | Hard | Factorial number system. |