Arrays · Core Array Techniques

Lexicographic Rearrangement

Finding the next arrangement of a fixed set of elements in dictionary order, in place, without generating every permutation.

  • 4 min read
  • 10 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. Where you'll see it
  4. Which tool for which job?
  5. Common mistakes
  6. Check yourself
  7. Key takeaways
  8. Quick revise
  9. Practice

Description

Lexicographic rearrangement finds the arrangement that comes right after (or right before) the current one in dictionary order: the next permutation. It works in place and in O(n), without listing all n! arrangements. The algorithm finds the rightmost place where the sequence can still grow, raises it by the smallest possible amount, and puts everything after it in its smallest order.

We'll go from simple to more technical:

  1. The pattern: find the pivot, swap with its successor, reverse the suffix.
  2. Where step-by-step enumeration shows up in production.
  3. The mistakes: the wrong swap partner, and confusing permutations with combinations.
  4. What it doesn't do: jumping straight to the k-th arrangement.

The approach

You could generate every permutation, sort them and pick the one after the current one. That takes O(n! * n) time and memory for a single step, which is hopeless past a handful of elements. You only need to look at the end of the array instead.

Think of the arrangement as a number, like 13542. To get the next larger one, change it as far to the right as possible. Read from the right while the digits keep rising: 2, 4, 5. That tail, 5 4 2, is already in its largest order, so changing it alone can't help. The first digit that breaks the rise, 3, is the pivot. Raise it by as little as possible, to the smallest digit in the tail that's bigger than it, which is 4. Then put the tail in its smallest order.

StepWhat it findsArray
Start1 3 5 4 2
1. Pivotfrom the right, the first value smaller than its right neighbor: 31 3 5 4 2
2. Swapfrom the right, the first value bigger than 3: 4. Swap them1 4 5 3 2
3. Reversethe part after the pivot, 5 3 2, becomes 2 3 51 4 2 3 5

So the arrangement after 13542 is 14235.

1. Scan right-to-left for the first index i where nums[i] < nums[i + 1] (the "pivot").
2. If found, scan right-to-left again for the first index j > i where nums[j] > nums[i],
   and swap them.
3. Reverse everything after index i - it was in non-increasing order, so reversing makes
   it ascending: the smallest possible arrangement of that suffix.

Why reverse instead of sort? After the swap, the tail is still in descending order. Reversing it gives ascending order in O(n). If there's no pivot at all, the array is the last arrangement (fully descending). Reversing the whole array then wraps around to the first one.

Where you'll see it

Test generators that try every ordering of a fixed set use this. So do searches that must stop and resume later. Each step needs only the current arrangement, so nothing else has to be stored, and the order is the same every run.

Which tool for which job?

You needUse
The next arrangement in dictionary ordernext permutation: pivot, swap, reverse
The previous arrangementthe mirror: flip every comparison
The k-th arrangement directlythe factorial number system
Every arrangement, in order, without duplicatessort, then step with next permutation
The next subset of the same sizethe next bitmask with the same number of 1s
All arrangements, order doesn't matterbacktracking or itertools.permutations

Common mistakes

MistakeWhat happensDo this instead
Swapping with the largest element of the suffixit skips arrangementsswap with the smallest element bigger than the pivot (first from the right)
Sorting the suffix after the swapcorrect, but O(n log n)reverse it - it's already in descending order
Strict > in the scans with duplicatesthe pivot or partner is wrong>= to find the pivot, <= to find the partner
Forgetting the last arrangementno pivot and nothing happensreverse the whole array (wrap to the first)
Using it for "next subset"wrong problema bitmask or a combination step

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. Why is the part after the pivot already the largest arrangement of its own values?

Show answer

Every position after the pivot failed the test that would have made it the pivot. So, read from the left, the tail never rises: it's in descending order. Descending order is always the largest arrangement of a set of values.

2. Why swap the pivot with the first bigger value from the right, and not with any bigger value?

Show answer

The tail is in descending order, so the first bigger value from the right is the smallest one that's still bigger than the pivot. Swapping in the smallest possible bigger value gives the very next arrangement, not just a bigger one.

3. What changes to turn next permutation into previous permutation?

Show answer

Every comparison flips. The pivot is the first value from the right that's bigger than its right neighbor. The partner is the largest value in the tail that's still smaller than the pivot. The tail ends up in descending order, its largest arrangement.

Key takeaways

  • The pivot is the rightmost position where a bigger arrangement can start. Everything after it is already as large as it can be.
  • Swap the pivot with the smallest bigger value in the tail, then reverse the tail.
  • With no pivot, the array is the last arrangement. Reversing it wraps to the first.
  • Previous permutation is the mirror image: flip every comparison.
  • It works because arrangements of a fixed set of values have a total order. It doesn't apply to subsets.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
Next arrangementpivot, swap, reverse
Previous arrangementthe mirror
The k-th arrangementfactorial number system
Distinct arrangements of a multisetsort, then step
Next subset of size kGosper's hack

Snippets worth knowing by heart

Java

int i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;            // the pivot
if (i >= 0) {
    int j = nums.length - 1;
    while (nums[j] <= nums[i]) j--;                      // smallest larger, from the right
    int t = nums[i]; nums[i] = nums[j]; nums[j] = t;
}
for (int l = i + 1, r = nums.length - 1; l < r; l++, r--) {   // reverse the suffix
    int t = nums[l]; nums[l] = nums[r]; nums[r] = t;
}

Python

i = len(nums) - 2
while i >= 0 and nums[i] >= nums[i + 1]:
    i -= 1                                   # the pivot
if i >= 0:
    j = len(nums) - 1
    while nums[j] <= nums[i]:
        j -= 1                               # smallest larger, from the right
    nums[i], nums[j] = nums[j], nums[i]
nums[i + 1:] = reversed(nums[i + 1:])        # reverse the suffix

The traps

  • The largest suffix element as the swap partner skips arrangements. Swap with the smallest element bigger than the pivot.
  • Sorting instead of reversing: correct, but O(n log n). The suffix is descending, so reverse it.
  • Strict comparisons with duplicates: the pivot or partner is wrong. Use >= to find the pivot, <= for the partner.
  • No wrap at the last arrangement: there's no pivot and nothing happens. Reverse the whole array.
  • Next subset is a different problem. Use a bitmask or a combination step.

Staff-level points, one line each

  • The suffix is the largest arrangement of its elements, so the prefix must change.
  • Average reversed suffix over all 8! permutations: 1.718 (about e - 1) - O(1) amortized.
  • [1, 1, 2, 2]: 6 distinct by stepping; itertools.permutations gives 24.
  • itertools.permutations follows positions: [2, 1, 3] starts (2, 1, 3), (2, 3, 1).
  • k-th permutation: index k // (n-1)! at each step.
  • Gosper's hack: 10 masks for C(5, 3), 00111 to 11100.

Say it in an interview

  • "The descending suffix can't grow, so I find the pivot just before it."
  • "I swap with the smallest larger element, then reverse the suffix to make it smallest."
  • "It's O(n) time and O(1) space, in place."
  • "For the k-th permutation I'd use the factorial number system instead of stepping."

Practice

This skill comes with 10 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Lexicographic Rearrangement free

Next Permutation

MediumProCoding problemJava · Python

Given an array of integers nums, rearrange it in place into the next lexicographically greater permutation of its elements. If no such permutation exists (the array is already the highest possible arrangement), rearrange it into the lowest possible order (sorted ascending)…

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Previous Permutation

MediumProCoding problemJava · Python

Given an array of integers nums, rearrange it in place into the previous lexicographically smaller permutation of its elements. If no such permutation exists (the array is already the lowest possible arrangement), rearrange it into the highest possible order (sorted descending)…

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Lexicographic Rearrangement free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime