Yasir Explains/Algorithms/Max-Flow, NP-Completeness, Backtracking & Branch and Bound/Backtracking: Permutations
Max-Flow, NP-Completeness, Backtracking & Branch and Bound

Backtracking: Permutations

On this page

What is backtracking?The permutations problemThe ideaStep-by-Step VisualizationPseudocodeComplexity AnalysisInteractive Playground
Max-Flow, NP-Completeness, Backtracking & Branch and Bound

Backtracking: Permutations

Generate all orderings of a set of numbers using backtracking: choose, explore, then un-choose.

What is backtracking?

Backtracking is a way to build a solution one small step at a time. At each step you make a choice, then try to continue from there. If that choice cannot lead anywhere new, you undo it and try the next option.

A simple way to remember the pattern is three words:

  1. Choose — pick an option that is still allowed.
  2. Explore — recurse to build the rest of the solution.
  3. Un-choose — undo the choice so you can try the next option.

This "choose, explore, un-choose" loop lets one piece of code explore every possibility without forgetting to clean up after itself.

The permutations problem

A permutation is just an ordering of items. Given n distinct items, we want to list every possible ordering.

How many are there? For the first position you have n choices, for the second position n − 1 choices, and so on. That gives n × (n − 1) × … × 1 = n! orderings.

For [1, 2, 3] there are 3! = 6 permutations:

[1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1]

The idea

We build one permutation in an array called current. A used[] array remembers which numbers we have already placed.

At each position we try every number that is not yet used: we choose it (mark it used and add it to current), recurse to fill the next position, and then un-choose it (remove it and mark it unused) so we can try the next number.

When current is full it is a complete permutation, so we save a copy.

Here is the recursion tree for [1, 2, 3]. Each path from the root down to a leaf is one finished permutation:

[] ├─ 1 │ ├─ 2 → [1,2,3] │ └─ 3 → [1,3,2] ├─ 2 │ ├─ 1 → [2,1,3] │ └─ 3 → [2,3,1] └─ 3 ├─ 1 → [3,1,2] └─ 2 → [3,2,1]

Step-by-Step Visualization

Watch the recursion run. The top row shows the available numbers (dimmed once used, highlighted blue when just picked). The middle shows the partial permutation being built. The bottom collects every completed permutation in green. Watch how a red "backtrack" step removes the last choice so the next one can be tried.

Available numbers
1
2
3
Current permutation
(empty — nothing chosen yet)
Results0 found
No complete permutations yet.
Start backtracking — build every ordering of [1, 2, 3].
Start backtracking — build every ordering of [1, 2, 3].
1 / 38
Speed

Pseudocode

The function calls itself once for every choice. The base case (a full current) records one finished permutation.

1PERMUTE(current, used)
2 if length(current) == n
3 output a COPY of current // one finished permutation
4 return
5 for i = 1 to n
6 if not used[i]
7 used[i] = true // choose
8 append items[i] to current
9 PERMUTE(current, used) // explore
10 remove last from current // un-choose
11 used[i] = false
12
13// start with: PERMUTE([], [false, false, ..., false])

Complexity Analysis

There are n! permutations, and copying each finished permutation costs O(n), giving O(n · n!) total work. The recursion goes at most n levels deep, and current/used use O(n) space, so the extra space is O(n) (not counting the stored output).

Complexity Analysis

Time Complexity

O(n · n!)

Space Complexity

O(n)

There are n! permutations; building each costs O(n) to copy. Recursion depth is O(n).

Growth Rate Comparison

n (input size)O(1)O(log n)O(n)O(n log n)O(n²)

Interactive Playground

Step through the backtracking process at your own pace. Use the controls to move forward and backward and watch how every ordering is discovered.

Available numbers
1
2
3
Current permutation
(empty — nothing chosen yet)
Results0 found
No complete permutations yet.
Start backtracking — build every ordering of [1, 2, 3].
Start backtracking — build every ordering of [1, 2, 3].
1 / 38
Speed