Next Permutation
Implement next permutation, which rearranges numbers into the lexicographical next greater permutation. If such arrangement is not possible, it must be rearranged as the lowest possible order (i.e., sorted in ascending order). The replacement must be in-place and use constant extra memory.
- 1 <= nums.length <= 100
- 0 <= nums[i] <= 100
nums = [1,2,3][1,3,2]nums = [3,2,1][1,2,3]nums = [1,1,5][1,5,1]Two definitions first, because the whole problem lives inside them. A permutation of an array is a rearrangement of exactly the same elements — same multiset, different order. Lexicographic order is dictionary order applied to sequences: compare position by position from the left, and the first position where they differ decides which is smaller — precisely how "apple" comes before "apply". Under this ordering, all rearrangements of the array line up from smallest ([1,2,3]-style, ascending) to largest (descending). Our task: given one arrangement, produce the one immediately after it in that lineup — the smallest rearrangement that is strictly greater. If the input is already the largest, wrap around to the smallest. And do it in-place with constant extra memory.
Generate every permutation, sort them, find ours, return the next one. There are N! arrangements — 10 elements give 3.6 million, 15 give over a trillion. Dead on arrival, but it defines what "next" means:
# Theoretical only:
all_perms = sorted(generate_all_permutations(nums))
current_idx = all_perms.find(nums)
return all_perms[current_idx + 1]How do you increase a sequence by the least possible amount? The same way counting works: change it as far to the right as you can, because under dictionary order the left positions dominate — any change at position i outweighs everything after it, so the earliest (leftmost) changed position should be as far right as possible.
So scan from the right asking: "can the suffix starting here be rearranged into something strictly larger?" Here is the key fact: a suffix that is non-increasing (each element ≥ the next, like [7, 4, 3, 1]) is already the largest possible arrangement of its own elements — rearranging a descending stack can only move a smaller element earlier, which makes it smaller. Such a suffix has no "next"; keep moving left. The scan stops at the first index i where nums[i] < nums[i+1] — the first place, from the right, where improvement is possible. Call it the pivot. If no such index exists, the entire array is descending: it is the global maximum, and per the problem's rule we reverse the whole thing to wrap to the global minimum.
At the pivot, the increase is unavoidable — so make it minimal, twice over. First: the new value at the pivot position should be the smallest element to its right that is still strictly greater than the pivot. The suffix is descending, so scanning from the far right, the first element greater than the pivot is exactly that one. Swap them. Second: everything after the pivot should now be as small as possible — and the smallest arrangement of any elements is ascending order. Conveniently, the suffix is still descending after the swap (the swapped-in value sits exactly where an equal-or-larger value sat, so the ordering holds), which means "sort ascending" is just "reverse" — O(N), no actual sorting.
# 1. Find the pivot: first index from the right with nums[i] < nums[i+1]
i = len(nums) - 2
while i >= 0 and nums[i] >= nums[i+1]:
i -= 1
if i >= 0:
# 2. Swap pivot with the smallest element to its right that beats it
j = len(nums) - 1
while nums[j] <= nums[i]:
j -= 1
nums[i], nums[j] = nums[j], nums[i]
# 3. The tail is descending; reverse it to make it the minimum
nums[i+1:] = nums[i+1:][::-1]Three scans, each at most N steps: O(N) time, O(1) space, in place. The transferable skeleton is the enumeration principle itself: to step to the "next" item in any ordered listing, change the least significant thing you legally can, then minimize everything after the change. That exact skeleton generates combinations, k-th permutations, and appears whenever a problem says "next greater arrangement". And the little lemma you proved on the way — "a descending run is the maximum arrangement of its elements" — is the reusable insight that makes the pivot scan work.
Next Permutation Logic
LEXICOGRAPHICAL RULE
We find the rightmost pivot point that can be increased, swap it with its smallest larger successor, and set the rest to the smallest order (reverse).
THE MAX CASE
If no pivot is found (descending order), we are at the absolute last permutation. We reverse the entire array to wrap back to the first.