Rearrange the numbers into the next greater permutation in lexicographic order, in place. Scan from the right for the first ascent (the pivot), swap it with the smallest larger value to its right, then reverse the tail — all in O(n) time and O(1) space.
Turn the array into the next permutation in dictionary order, in place. For nums=[1,2,3] the answer is [1,3,2]. For nums=[1,1,5] it is [1,5,1]. If the array is the very last permutation (fully descending) like [3,2,1], wrap around to the first: [1,2,3].
i where nums[i] < nums[i+1] (the pivot). Replace nums[i] with the smallest value to its right that is still larger, then make the now-descending tail as small as possible by reversing it.nums[i] >= nums[i+1]. The first place this breaks is the pivot i— because everything past it is already maximal and can't produce a bigger number.j with nums[j] > nums[i] and swap. Since the tail is descending, that first match is the smallest value that still exceeds the pivot — the minimal legal bump.i is still descending; reversing it makes it ascending = the smallest ordering, giving the closest larger permutation.Everything happens with index math and in-place swaps — no auxiliary array. The work is three linear passes at most (find pivot, find swap target, reverse), so it is O(n) time and O(1) extra space.
i where nums[i] < nums[i+1].1function nextPermutation(nums: number[]): void {2▶ const n = nums.length;34 // 1. find pivot: first i from the right with nums[i] < nums[i + 1]5 let i = n - 2;6 while (i >= 0 && nums[i] >= nums[i + 1]) i--;78 // 2. if a pivot exists, swap it with the next-larger value to its right9 if (i >= 0) {10 let j = n - 1;11 while (nums[j] <= nums[i]) j--;12 [nums[i], nums[j]] = [nums[j], nums[i]];13 }1415 // 3. reverse the suffix after i so it becomes the smallest arrangement16 let lo = i + 1, hi = n - 1;17 while (lo < hi) {18 [nums[lo], nums[hi]] = [nums[hi], nums[lo]];19 lo++; hi--;20 }21}
function nextPermutation(nums: number[]): void {
const n = nums.length;
// 1. find pivot: first i from the right with nums[i] < nums[i + 1]
let i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
// 2. if a pivot exists, swap it with the next-larger value to its right
if (i >= 0) {
let j = n - 1;
while (nums[j] <= nums[i]) j--;
[nums[i], nums[j]] = [nums[j], nums[i]];
}
// 3. reverse the suffix after i so it becomes the smallest arrangement
let lo = i + 1, hi = n - 1;
while (lo < hi) {
[nums[lo], nums[hi]] = [nums[hi], nums[lo]];
lo++; hi--;
}
}n-2, move left while the array is non-increasing (nums[i] >= nums[i+1]). The first index where this fails is the pivot i; if we fall off the left end, i = -1 and the array was fully descending.j with nums[j] > nums[i]. Because the suffix descends, that first match is the smallest value exceeding the pivot — swapping yields the minimal increase to the prefix.0) the suffix after i is descending. A two-pointer reverse turns it ascending — the smallest tail — so the whole array is the closest larger permutation. When i = -1, this reverses the entire array.i = -1; we skip the swap and reverse the whole array, wrapping to the smallest (ascending) permutation.>= in the pivot scan and > in the swap scan already handle ties correctly — e.g. [1,1,5] → [1,5,1].function nextPermutation(nums: number[]): void {
const n = nums.length;
// 1. find pivot: first i from the right with nums[i] < nums[i + 1]
let i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
// 2. if a pivot exists, swap it with the next-larger value to its right
if (i >= 0) {
let j = n - 1;
while (nums[j] <= nums[i]) j--;
[nums[i], nums[j]] = [nums[j], nums[i]];
}
// 3. reverse the suffix after i so it becomes the smallest arrangement
let lo = i + 1, hi = n - 1;
while (lo < hi) {
[nums[lo], nums[hi]] = [nums[hi], nums[lo]];
lo++; hi--;
}
}Generate every permutation, sort them lexicographically, find the current one, and return the one after it (wrapping to the first). Conceptually obvious but combinatorially explosive.
function nextPermutation(nums: number[]): void {
const perms: number[][] = [];
const permute = (arr: number[], cur: number[]): void => {
if (arr.length === 0) { perms.push([...cur]); return; }
for (let k = 0; k < arr.length; k++) {
permute([...arr.slice(0, k), ...arr.slice(k + 1)], [...cur, arr[k]]);
}
};
permute(nums, []);
perms.sort((a, b) => a.findIndex((v, k) => v !== b[k]) === -1
? 0 : a[a.findIndex((v, k) => v !== b[k])] - b[a.findIndex((v, k) => v !== b[k])]);
const key = (p: number[]): string => p.join(',');
const idx = perms.findIndex((p) => key(p) === key(nums));
const next = perms[(idx + 1) % perms.length];
for (let k = 0; k < nums.length; k++) nums[k] = next[k];
}n! permutations — unusable past a handful of elements, and it ignores the O(1)-space requirement. The pivot/swap/reverse method gets the same answer in a single in-place O(n) pass.| "next permutation in place" | pivot → swap → reverse tail |
| suffix already descending | cannot grow → look further left |
| swap target on a descending tail | first-from-right that beats pivot |
| fully descending array | no pivot → reverse everything |
let i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--; // pivot
if (i >= 0) {
let j = nums.length - 1;
while (nums[j] <= nums[i]) j--; // next-larger
[nums[i], nums[j]] = [nums[j], nums[i]]; // swap
}
let lo = i + 1, hi = nums.length - 1; // reverse tail
while (lo < hi) { [nums[lo], nums[hi]] = [nums[hi], nums[lo]]; lo++; hi--; }i with nums[i] < nums[i+1] — the first ascent scanning from the right.