Reordering a sequence into the very next one in dictionary order. Not by listing all N! arrangements — by making the smallest possible change as far to the right as it can go.
List every permutation and sort them lexicographically; "next permutation" is the one right after the current
array. [1,2,3] → [1,3,2], [2,3,1] → [3,1,2]. If the array is already the largest
([3,2,1]), wrap around to the smallest ([1,2,3]). Generating all N! arrangements is
impossible even for N=100, and the constraint is in-place, O(1) space — so the next arrangement
has to be derived directly.
Lexicographic order is dictionary order: compare left to right, and the first differing position decides everything. So a change at an early index causes a huge jump, a change at a late index a tiny one. To land on the very next arrangement, keep the longest possible prefix untouched and edit as far right as you can.
It's the same instinct as incrementing an odometer: 129999 ticks the rightmost digits first,
holding the high-order prefix as long as it can.
A car's trip meter rolls the rightmost wheels first and only disturbs a higher wheel when the ones below max out. Next permutation is that instinct on unsorted digits.
Walk backward down a descending slope until you hit the last rise. That rise is the pivot — the final place where a bigger step is still available before the tail runs downhill.
The tail after the pivot is already stacked biggest-first (a maximal block). Once you nudge the pivot up, flip that block to smallest-first — no sorting needed, just a reverse.
Set an array and step through. Phase 1 scans right-to-left, tinting the descending tail teal until it finds the pivot (the last rise). Phase 2 scans back for the smallest tail value greater than the pivot — the successor — and swaps. Phase 3 reverses the tail into ascending order.
Try 3 2 1 (no pivot → whole array reverses) or
1 3 2 (why you can't just swap the last two).
Every array splits into three zones. The prefix stays frozen. The pivot is the one element that goes up. The tail after it is already descending — a maximal block — so it just needs flipping.
Choose the successor 3, swap it with the pivot, then minimize the tail:
Final: [1, 3, 1, 2, 4, 7]. The prefix never moved, the pivot rose by the least it could, and the
tail is as small as it can be — the definition of "next."
| Input | Pivot | Successor | After swap | Reverse tail | Result |
|---|---|---|---|---|---|
[1,2,3] |
i=1 (2) | j=2 (3) | [1,3,2] | [2]→[2] | [1,3,2] |
[1,3,2] |
i=0 (1) | j=2 (2) | [2,3,1] | [3,1]→[1,3] | [2,1,3] |
[3,2,1] |
none | — | — | reverse all | [1,2,3] |
Row 2 is the instructive one: naively swapping the last two of [1,3,2] gives [1,2,3],
which is smaller. The pivot is actually the 1, and reversing the tail afterward is what
makes the result correct.
void nextPermutation(int[] nums) { int n = nums.length, i = n - 2; // 1. pivot: rightmost i with nums[i] < nums[i+1] while (i >= 0 && nums[i] >= nums[i + 1]) i--; if (i >= 0) { // 2. successor: rightmost value > pivot int j = n - 1; while (nums[j] <= nums[i]) j--; swap(nums, i, j); } // 3. reverse the tail (whole array if no pivot) reverse(nums, i + 1, n - 1); }
reverse(nums, 0, n−1) flips the whole descending array. No special branch
needed.O(N) time, O(1) space. Three sequential linear passes, all edits in-place. Sorting the tail would also work but costs O(N log N) — reversing exploits the structure that's already there.
Changing the first place that can increase makes too big a jump. Next permutation preserves the longest prefix — scan right to left.
Pivot 2, tail [7,5,3,1] → swapping 7 overshoots. You want 3, the smallest value
greater than the pivot.
[1,3,2] pivot-swap gives [2,3,1]; stopping there is wrong. Minimizing the tail (→
[2,1,3]) is essential.
The successor must be strictly greater — swapping with an equal value doesn't increase the
permutation. Stop only when nums[j] > nums[i].
That destroys the prefix you deliberately kept. Only [pivot+1 … n−1] may be rearranged.
[1,3,2] rotated is [2,1,3]-ish by luck, but ordering is lexicographic, not
cyclic. Don't reach for rotations.
Put together, the result is larger than the input (the pivot went up) and no valid permutation sits between
them (the increase was minimal and the tail minimized). That's exactly "next." Duplicates don't break it — the
strict > on the successor is what keeps the step honest.
Array positions have descending importance — index 0 dominates everything after it. So the whole recipe is a priority game: preserve the high-priority prefix, make the smallest legal improvement, then minimize the low-priority remainder. The same three-beat move powers a family of problems.
The transferable move: when a problem asks for the next or smallest lexicographic result, don't enumerate — find the rightmost decision point, change it minimally, and rebuild the tail as small as possible.