Generating Permutations

Backtracking that generates all n! orderings by choosing an unused element for each position and undoing it on return.

Worth knowing first

#How does it work?

A permutation is an ordering of the elements. n distinct elements have n! (n factorial) permutations: n choices for the first position, n − 1 for the second, and so on.

With backtracking, each position gets an element not used yet; it is marked as used and we move to the next position. When every position is filled, a permutation is recorded. On the way back the choice is undone and the next element is tried for the same position.

The search tree has n nodes on its first level and n · (n − 1) on the second; it has n! leaves. Trying elements in increasing order produces the permutations in lexicographic order.

#Try it yourself

$ permutations --interactive

We generate every ordering of the numbers 1 … n. Each level picks a number not used yet; when a branch is done the choice is undone.

VisitingNewRemovingFound / read

#Step by step

  1. 01Start with an empty chosen list and no element used.
  2. 02For each unused element: choose it, mark it used and move to the next position.
  3. 03If every position is filled, record the permutation.
  4. 04On the way back, undo the choice and the mark (backtracking).

#Example code

The same algorithm in 8 languages. Every program is compiled, run and checked to print the same output.

def permutations(items: list) -> list:
    out, chosen, used = [], [], [False] * len(items)

    def visit() -> None:
        if len(chosen) == len(items):
            out.append(list(chosen))
            return
        for i, x in enumerate(items):
            if used[i]:
                continue
            used[i] = True
            chosen.append(x)
            visit()
            chosen.pop()     # undo the choice (backtrack)
            used[i] = False

    visit()
    return out


for p in permutations([1, 2, 3]):
    print(" ".join(map(str, p)))

#Complexity

OperationTime
Number of permutationsn!
Generating them allO(n · n!)
Memory (recursion + marks)O(n)
In-place swappingO(n · n!), no extra array

n! grows very fast: 10 elements mean 3.6 million permutations, 13 elements over 6 billion. Trying every permutation only works for small n; larger problems need pruning, DP or heuristics.

#When to use it?

Brute-force searches over small orderings (e.g. a travelling salesman with a few cities), generating anagrams, trying every order of test steps and puzzle solvers all generate permutations.

#Practice

Log in to answer questions and save your progress.

Easy

1/3

How many permutations do n distinct elements have?

  • 1n!
  • 22ⁿ
  • 3n²
  • 4n

Medium

1/1

How many nodes (excluding the root) does the search tree have for n = 3?

  • 115
  • 26
  • 39
  • 427

Hard

1/1

What is the time complexity of generating all permutations?

  • 1O(n · n!)
  • 2O(n!)
  • 3O(2ⁿ)
  • 4O(n²)