Mustaque Nadim Academy
Arrays & Strings

Next Permutation

Given an arrangement, what’s the very next one in dictionary order? There’s an elegant in-place way to find it.

The problem

Think of the odometer in an old car, but each digit can be any value and no digit repeats. You're showing arrangements of [1, 2, 3] in dictionary order: 123, 132, 213, 231, 312, 321. Someone hands you 123 and asks for the next one, 132. Hand them 321 and there is no next — you wrap back to 123.

The task: given one arrangement, produce the immediately next arrangement in lexicographic (dictionary) order, using the same elements. And do it in place, without listing all the permutations first.

A first attempt

The brute-force route: generate every permutation, sort them all, find yours in the list, and return the one after it. With n elements there are n! permutations — for just 12 elements that's nearly half a billion arrangements to build and sort. You'd burn O(n!) time and memory to answer a question about a single step. There has to be local structure we can exploit instead.

The insight

Read the arrangement from the right and notice what makes 321 the last one: it's fully descending. A descending tail is already maxed out — it can't get any bigger. So the only way to increase the number by the smallest possible amount is:

  1. Find the rightmost spot where the order breaks — an element smaller than the one just after it. Call its index the pivot.
  2. Swap the pivot with the smallest element to its right that still beats it. This nudges the number up by the least amount possible at that position.
  3. The tail after the pivot is still descending; reverse it to make it ascending — the smallest possible ending.

If there's no pivot at all, the whole thing was descending (the last permutation), so just reverse it to wrap around to the first.

How it works

Take [1, 3, 5, 4, 2]. The next permutation is [1, 4, 2, 3, 5].

Find the pivot from the right

Scan right-to-left for the first index i where arr[i] < arr[i + 1]. Here 5 > 4 > 2 is descending, but 3 < 5 — so the pivot is arr[1] = 3.

Find the successor to swap in

In the descending tail [5, 4, 2], find the rightmost element still larger than the pivot 3. That's 4. Swap it with the pivot: [1, 4, 5, 3, 2].

Reverse the tail

Everything after the pivot position is still descending ([5, 3, 2]). Reverse it to get the smallest ordering: [2, 3, 5]. Result: [1, 4, 2, 3, 5].

Handle the wrap-around

If step 1 finds no pivot (the array was fully descending, like [3, 2, 1]), reversing the whole array gives the first permutation [1, 2, 3].

[1, 3, 5, 4, 2]
    ^pivot=3 (arr[1] < arr[2])
find rightmost > 3 in tail [5,4,2] -> 4, swap:
[1, 4, 5, 3, 2]
reverse tail after pivot [5,3,2] -> [2,3,5]:
[1, 4, 2, 3, 5]   ✓

The code

The tail reversal reuses the two-pointer sweep from Array Traversal Tricks.

def next_permutation(arr):
    n = len(arr)
    i = n - 2
    while i >= 0 and arr[i] >= arr[i + 1]:   # find the pivot
        i -= 1
    if i >= 0:                               # not the last permutation
        j = n - 1
        while arr[j] <= arr[i]:              # rightmost value bigger than pivot
            j -= 1
        arr[i], arr[j] = arr[j], arr[i]
    arr[i + 1:] = reversed(arr[i + 1:])      # reverse the tail (whole array if i == -1)
function nextPermutation(arr: number[]): void {
  const n = arr.length;
  let i = n - 2;
  while (i >= 0 && arr[i] >= arr[i + 1]) i--;
  if (i >= 0) {
    let j = n - 1;
    while (arr[j] <= arr[i]) j--;
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  let lo = i + 1, hi = n - 1;                // reverse the tail
  while (lo < hi) {
    [arr[lo], arr[hi]] = [arr[hi], arr[lo]];
    lo++;
    hi--;
  }
}
void nextPermutation(int[] arr) {
    int n = arr.length, i = n - 2;
    while (i >= 0 && arr[i] >= arr[i + 1]) i--;
    if (i >= 0) {
        int j = n - 1;
        while (arr[j] <= arr[i]) j--;
        int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
    }
    int lo = i + 1, hi = n - 1;
    while (lo < hi) {
        int tmp = arr[lo]; arr[lo] = arr[hi]; arr[hi] = tmp;
        lo++; hi--;
    }
}
void next_permutation(int *arr, int n) {
    int i = n - 2;
    while (i >= 0 && arr[i] >= arr[i + 1]) i--;
    if (i >= 0) {
        int j = n - 1;
        while (arr[j] <= arr[i]) j--;
        int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
    }
    int lo = i + 1, hi = n - 1;
    while (lo < hi) {
        int tmp = arr[lo]; arr[lo] = arr[hi]; arr[hi] = tmp;
        lo++; hi--;
    }
}
#include <vector>
#include <algorithm>
using namespace std;

void nextPermutation(vector<int>& arr) {
    int n = (int)arr.size(), i = n - 2;
    while (i >= 0 && arr[i] >= arr[i + 1]) i--;
    if (i >= 0) {
        int j = n - 1;
        while (arr[j] <= arr[i]) j--;
        swap(arr[i], arr[j]);
    }
    reverse(arr.begin() + (i + 1), arr.end());
}

Complexity

ApproachTimeSpaceNote
Generate & sort allO(n!·n)O(n!)builds every arrangement — infeasible
Pivot, swap, reverseO(n)O(1)at most three linear passes, in place

Three simple scans — find pivot, find successor, reverse tail — and never more than O(n) work total.

When to use it

Repeat it to list every permutation in order

Call next_permutation in a loop starting from the sorted array until it wraps back to the start, and you get all n! permutations in lexicographic order using O(1) extra space — no recursion stack. It's the iterative alternative to backtracking permutations.

Practice

Recap

  • Next permutation finds the immediately-larger arrangement in dictionary order in O(n) time and O(1) space — no need to enumerate all n! of them.
  • The recipe: find the rightmost pivot where order breaks, swap it with the smallest larger element to its right, then reverse the descending tail.
  • A fully descending array has no pivot; reversing the whole thing wraps it back to the first permutation.

How is this guide?

Last updated on

On this page