Next Permutation
Table of Contents + β
Next Permutation trips up a lot of people. The idea sounds simple. Find the next bigger arrangement of the same numbers. But the clean solution is a precise dance of three small steps. This question tests whether you can spot a pattern and turn it into exact code.
π― The Problem
You get an array of numbers and you want the next bigger arrangement of those same numbers. An arrangement of the same numbers is called a permutation. Here are the rules.
- List all arrangements from smallest to largest, then return the one right after the current one.
- If the current one is already the largest, wrap around to the smallest.
- You must change the array in place. So you cannot build a big new list. You only swap and reverse inside the array you were given.
Let us say the array is [1, 2, 3]. The next bigger arrangement is [1, 3, 2]. For [3, 2, 1], which is already the largest, you wrap around to [1, 2, 3].
Input: nums = [1, 2, 3]Output: [1, 3, 2]
Explanation: [1, 3, 2] is the smallest arrangement that is larger than [1, 2, 3]Here is a picture of what βnextβ means. The arrangements sit in order from small to large. We want the one right after the current one.
π’ Approach 1: Generate All Permutations (Brute Force)
The idea in one line: build every arrangement, sort them, then return the one after the current.
The idea:
- List every permutation of the numbers.
- Sort that list from smallest to largest.
- Find the current arrangement and return the next one.
Why it is weak:
- For n numbers there are n factorial arrangements.
- So this is O(n!) time. Far too slow past tiny arrays.
- It also holds every arrangement in memory, so it is heavy on space.
Here is the brute-force idea as code:
from itertools import permutations
def next_permutation(nums): all_orders = sorted(set(permutations(nums))) current = tuple(nums) index = all_orders.index(current)
if index == len(all_orders) - 1: nums[:] = list(all_orders[0]) else: nums[:] = list(all_orders[index + 1])
nums = [1, 2, 3]next_permutation(nums)print(nums)β‘ Approach 2: Pivot, Swap, Reverse (Best)
The idea in one line: bump the rightmost spot that can grow, then make the tail as small as possible.
Find the pivot:
- Scan from the right for the first index
iwherenums[i] < nums[i + 1]. - That spot is the pivot, the number we bump up.
- The tail to the right of the pivot is already in falling order, so it is the largest that tail can be.
- No pivot means the whole array is the largest. Then just reverse it to get the smallest.
Swap the pivot up:
- Scan from the right again.
- Find the smallest value still bigger than the pivot.
- Swap those two. Now the pivot spot holds the next bigger value it can take.
Reverse the tail:
- The tail after the pivot is still in falling order.
- Reverse it into rising order.
- That gives the smallest ending after the bump.
Why it is fast:
- A few passes from the right and one reverse.
- Each element is touched a constant number of times.
- So it runs in O(n) time and uses no extra array.
This picture shows the three steps on [1, 2, 3]. Follow the pivot, the swap, then the reverse.
Steps to Solve
- Walk from the right and find the first index
iwherenums[i] < nums[i + 1]. Callithe pivot. - If no such pivot exists, reverse the whole array and stop.
- Walk from the right and find the first index
jwherenums[j] > nums[i]. - Swap
nums[i]andnums[j]. - Reverse the part of the array after index
ito put the tail in rising order.
This Python version changes the list in place using the same three steps.
def next_permutation(nums): n = len(nums) i = n - 2 while i >= 0 and nums[i] >= nums[i + 1]: # find the pivot i -= 1 if i >= 0: j = n - 1 while nums[j] <= nums[i]: # find just-bigger value j -= 1 nums[i], nums[j] = nums[j], nums[i] # bump the pivot up # reverse the tail after the pivot to make it smallest nums[i + 1:] = reversed(nums[i + 1:])
nums = [1, 2, 3]next_permutation(nums)print(nums)The output of the above code will be:
[1, 3, 2]Let us walk through the Python version line by line. Code first, then the why.
def next_permutation(nums): n = len(nums) i = n - 2 while i >= 0 and nums[i] >= nums[i + 1]: i -= 1 if i >= 0: j = n - 1 while nums[j] <= nums[i]: j -= 1 nums[i], nums[j] = nums[j], nums[i] nums[i + 1:] = reversed(nums[i + 1:])i = n - 2 starts the search one step from the right end. We compare each element with the one after it. So we never need to look past the last index.
while i >= 0 and nums[i] >= nums[i + 1]: walks left until the order stops rising. The first place where a number is smaller than its right neighbor is the pivot. If we walk all the way off the left edge, i becomes -1, which means no pivot exists.
if i >= 0: runs only when we found a pivot. If there was no pivot, we skip straight to the reverse, which turns the largest arrangement back into the smallest.
while nums[j] <= nums[i]: finds the smallest value on the right that is still bigger than the pivot. The tail is in falling order, so the first value from the right that beats the pivot is exactly the one we want.
nums[i], nums[j] = nums[j], nums[i] swaps them. Now the pivot position holds the next allowed bigger value.
nums[i + 1:] = reversed(nums[i + 1:]) reverses the tail. The tail was in falling order, so reversing it makes it rise. That gives the smallest possible ending after the bump, which is exactly the next permutation.
β±οΈ Time and Space Complexity
The brute force builds every arrangement, so it is hopelessly slow and memory heavy. The pivot method makes a few passes from the right and one reverse, so it touches each element a constant number of times. That gives O(n) time and no extra array, which is O(1) space.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Brute force (all permutations) | O(n! Γ n) | O(n! Γ n) |
| Pivot, swap, reverse (in place) | O(n) | O(1) |
Tip
The three steps are pivot, swap, reverse. Say them in that order in the interview. Then dry run a small example out loud. That dry run is what proves to the interviewer that you actually understand it.
π§© Key Takeaways
- β The next permutation is the smallest arrangement that is still bigger than the current one.
- β Find the pivot, which is the first drop scanning from the right.
- β Swap the pivot with the smallest value to its right that is still bigger.
- β Reverse the tail after the pivot to make the ending as small as possible.
- β If there is no pivot, the array is the largest, so reverse the whole thing to get the smallest.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What is the pivot in the Next Permutation algorithm?
Why: The pivot is the first spot, scanning from the right, where a number is smaller than its right neighbor.
- 2
What do you do when no pivot is found?
Why: No pivot means the array is the largest arrangement, so reversing it gives the smallest one.
- 3
After swapping the pivot, why do we reverse the tail after it?
Why: The tail was in falling order, so reversing it makes it rise, giving the smallest possible ending.
- 4
What is the time and space complexity of the pivot, swap, reverse solution?
Why: A few passes from the right and one reverse give O(n) time, and it changes the array in place for O(1) space.