Next Permutation
Imagine you have a list of numbers representing a password combination, and you want to find the next possible combination in lexicographical order to try next.
Given an array of integers nums representing a permutation, modify nums in-place to the next lexicographically greater permutation of numbers. If such arrangement is not possible, rearrange it as the lowest possible order (i.e., sorted in ascending order). The replacement must be in-place with only constant extra memory.
1 ≤ nums.length ≤ 10^5-10^9 ≤ nums[i] ≤ 10^9"[1,2,3]"[1,3,2]The next permutation after 1,2,3 is 1,3,2.
"[3,2,1]"[1,2,3]3,2,1 is the highest permutation, so we return the lowest permutation 1,2,3.
"[1,1,5]"[1,5,1]Next permutation after 1,1,5 is 1,5,1.
- Single element array [1] → output [1]
- All elements equal [2,2,2] → output [2,2,2]
- Strictly descending order [5,4,3,2,1] → output [1,2,3,4,5]
- Array with duplicates [1,3,2,3] → output [1,3,3,2]
Code fails to reset to lowest permutation, causing wrong output
✅ Add condition to reverse entire array if no pivot found
Next permutation is incorrect or not lexicographically next
✅ Scan from right to find the first element greater than pivot to swap
Suffix remains in descending order, so permutation is not minimal next
✅ Reverse the suffix after pivot to get the smallest lex order suffix
Solution is inefficient and may time out on large inputs
✅ Implement in-place approach with O(1) extra space
Next permutation may skip valid permutations or produce duplicates
✅ Algorithm naturally handles duplicates by scanning and swapping correctly
Intuition
Generate all permutations of the array, sort them lexicographically, then find the current permutation and return the next one in order.
Algorithm
- Generate all permutations of the input array.
- Sort all permutations lexicographically.
- Find the index of the current permutation in the sorted list.
- Return the permutation at the next index, or the first if current is last.
from itertools import permutations
def next_permutation(nums):
perms = sorted(set(permutations(nums)))
curr = tuple(nums)
idx = perms.index(curr)
next_idx = (idx + 1) % len(perms)
nums[:] = perms[next_idx]
# Driver code
if __name__ == '__main__':
arr = [1,2,3]
next_permutation(arr)
print(arr) # Output: [1,3,2]from itertools import permutationsImport permutations to generate all permutations easilyperms = sorted(set(permutations(nums)))Generate all unique permutations and sort them lex orderidx = perms.index(curr)Find the current permutation's index in the sorted listnums[:] = perms[next_idx]Modify input array in-place to the next permutationimport java.util.*;
public class NextPermutationBrute {
public static void nextPermutation(int[] nums) {
List<List<Integer>> perms = new ArrayList<>();
permute(nums, 0, perms);
perms.sort((a,b) -> {
for (int i = 0; i < a.size(); i++) {
if (!a.get(i).equals(b.get(i))) return a.get(i) - b.get(i);
}
return 0;
});
List<Integer> curr = new ArrayList<>();
for (int num : nums) curr.add(num);
int idx = perms.indexOf(curr);
List<Integer> next = perms.get((idx + 1) % perms.size());
for (int i = 0; i < nums.length; i++) nums[i] = next.get(i);
}
private static void permute(int[] nums, int start, List<List<Integer>> perms) {
if (start == nums.length) {
List<Integer> perm = new ArrayList<>();
for (int num : nums) perm.add(num);
if (!perms.contains(perm)) perms.add(perm);
return;
}
for (int i = start; i < nums.length; i++) {
swap(nums, start, i);
permute(nums, start + 1, perms);
swap(nums, start, i);
}
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp;
}
// Driver code
public static void main(String[] args) {
int[] arr = {1,2,3};
nextPermutation(arr);
System.out.println(Arrays.toString(arr)); // Output: [1,3,2]
}
}List<List<Integer>> perms = new ArrayList<>();Store all permutations generatedpermute(nums, 0, perms);Generate all permutations recursivelyperms.sort((a,b) -> {...});Sort permutations lex order using comparatorint idx = perms.indexOf(curr);Find current permutation index to get next#include <bits/stdc++.h>
using namespace std;
void permute(vector<int>& nums, int start, vector<vector<int>>& perms) {
if (start == (int)nums.size()) {
perms.push_back(nums);
return;
}
for (int i = start; i < (int)nums.size(); i++) {
swap(nums[start], nums[i]);
permute(nums, start + 1, perms);
swap(nums[start], nums[i]);
}
}
void nextPermutation(vector<int>& nums) {
vector<vector<int>> perms;
permute(nums, 0, perms);
sort(perms.begin(), perms.end());
auto it = find(perms.begin(), perms.end(), nums);
int idx = distance(perms.begin(), it);
nums = perms[(idx + 1) % perms.size()];
}
int main() {
vector<int> arr = {1,2,3};
nextPermutation(arr);
for (int x : arr) cout << x << ' '; // Output: 1 3 2
cout << '\n';
return 0;
}void permute(vector<int>& nums, int start, vector<vector<int>>& perms)Recursive function to generate all permutationssort(perms.begin(), perms.end());Sort all permutations lexicographicallyauto it = find(perms.begin(), perms.end(), nums);Find current permutation's positionnums = perms[(idx + 1) % perms.size()];Assign next permutation or wrap to firstfunction permute(nums, start, perms) {
if (start === nums.length) {
perms.push(nums.slice());
return;
}
for (let i = start; i < nums.length; i++) {
[nums[start], nums[i]] = [nums[i], nums[start]];
permute(nums, start + 1, perms);
[nums[start], nums[i]] = [nums[i], nums[start]];
}
}
function nextPermutation(nums) {
let perms = [];
permute(nums, 0, perms);
perms.sort((a,b) => {
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return a[i] - b[i];
}
return 0;
});
let currStr = nums.join(',');
let idx = perms.findIndex(p => p.join(',') === currStr);
let next = perms[(idx + 1) % perms.length];
for (let i = 0; i < nums.length; i++) nums[i] = next[i];
}
// Driver code
let arr = [1,2,3];
nextPermutation(arr);
console.log(arr); // Output: [1,3,2]function permute(nums, start, perms)Recursive helper to generate permutationsperms.sort((a,b) => {...});Sort permutations lex order for indexinglet idx = perms.findIndex(p => p.join(',') === currStr);Find current permutation indexfor (let i = 0; i < nums.length; i++) nums[i] = next[i];Overwrite input array in-placeO(n! * n log n) due to generating all permutations and sortingO(n! * n) to store all permutationsGenerating all permutations is factorial in n, sorting them adds n log n factor, and storing them requires large memory.
This approach is too slow for large inputs but helps understand the problem and verify correctness on small inputs.
Intuition
Traverse from the end to find the first decreasing element (pivot), then find the smallest element larger than pivot to the right, swap them, and reverse the suffix after pivot.
Algorithm
- Scan from right to left to find the first index 'i' where nums[i] < nums[i+1].
- If no such index exists, reverse the entire array and return.
- Otherwise, scan from right to find the first index 'j' where nums[j] > nums[i].
- Swap nums[i] and nums[j].
- Reverse the subarray nums[i+1:] to get the next permutation.
def next_permutation(nums):
i = len(nums) - 2
while i >= 0 and nums[i] >= nums[i + 1]:
i -= 1
if i >= 0:
j = len(nums) - 1
while nums[j] <= nums[i]:
j -= 1
nums[i], nums[j] = nums[j], nums[i]
left, right = i + 1, len(nums) - 1
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
# Driver code
if __name__ == '__main__':
arr = [1,2,3]
next_permutation(arr)
print(arr) # Output: [1,3,2]i = len(nums) - 2Start from second last element to find pivotwhile i >= 0 and nums[i] >= nums[i + 1]Find first decreasing element from rightif i >= 0:If pivot found, find element to swap withwhile nums[j] <= nums[i]Find rightmost element greater than pivotimport java.util.*;
public class NextPermutationBetter {
public static void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0) {
int j = nums.length - 1;
while (nums[j] <= nums[i]) j--;
swap(nums, i, j);
}
reverse(nums, i + 1, nums.length - 1);
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp;
}
private static void reverse(int[] nums, int start, int end) {
while (start < end) {
swap(nums, start++, end--);
}
}
// Driver code
public static void main(String[] args) {
int[] arr = {1,2,3};
nextPermutation(arr);
System.out.println(Arrays.toString(arr)); // Output: [1,3,2]
}
}int i = nums.length - 2;Start from second last index to find pivotwhile (i >= 0 && nums[i] >= nums[i + 1]) i--;Find first decreasing element from rightif (i >= 0)If pivot found, find element to swap withreverse(nums, i + 1, nums.length - 1);Reverse suffix to get next permutation#include <bits/stdc++.h>
using namespace std;
void nextPermutation(vector<int>& nums) {
int i = (int)nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0) {
int j = (int)nums.size() - 1;
while (nums[j] <= nums[i]) j--;
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
int main() {
vector<int> arr = {1,2,3};
nextPermutation(arr);
for (int x : arr) cout << x << ' '; // Output: 1 3 2
cout << '\n';
return 0;
}int i = (int)nums.size() - 2;Start from second last element to find pivotwhile (i >= 0 && nums[i] >= nums[i + 1]) i--;Find first decreasing element from rightif (i >= 0)If pivot found, find element to swap withreverse(nums.begin() + i + 1, nums.end());Reverse suffix to get next permutationfunction nextPermutation(nums) {
let i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0) {
let j = nums.length - 1;
while (nums[j] <= nums[i]) j--;
[nums[i], nums[j]] = [nums[j], nums[i]];
}
let left = i + 1, right = nums.length - 1;
while (left < right) {
[nums[left], nums[right]] = [nums[right], nums[left]];
left++;
right--;
}
}
// Driver code
let arr = [1,2,3];
nextPermutation(arr);
console.log(arr); // Output: [1,3,2]let i = nums.length - 2;Start from second last index to find pivotwhile (i >= 0 && nums[i] >= nums[i + 1]) i--;Find first decreasing element from rightif (i >= 0)If pivot found, find element to swap withwhile (left < right)Reverse suffix to get next permutationO(n)O(1)We scan the array from the end a few times and reverse a suffix in-place, all linear operations.
This is the optimal approach expected in interviews for this problem.
Intuition
By scanning from the right and swapping only necessary elements, then reversing the suffix in-place, we avoid extra memory and achieve optimal performance.
Algorithm
- Find the pivot index from right where nums[i] < nums[i+1].
- If pivot not found, reverse entire array and return.
- Find the rightmost successor to pivot greater than nums[i].
- Swap pivot and successor.
- Reverse the suffix starting at pivot+1.
def next_permutation(nums):
i = len(nums) - 2
while i >= 0 and nums[i] >= nums[i + 1]:
i -= 1
if i >= 0:
j = len(nums) - 1
while nums[j] <= nums[i]:
j -= 1
nums[i], nums[j] = nums[j], nums[i]
left, right = i + 1, len(nums) - 1
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
# Driver code
if __name__ == '__main__':
arr = [1,2,3]
next_permutation(arr)
print(arr) # Output: [1,3,2]i = len(nums) - 2Start from second last element to find pivotwhile i >= 0 and nums[i] >= nums[i + 1]Find first decreasing element from rightif i >= 0:If pivot found, find element to swap withwhile left < rightReverse suffix in-place to get next permutationimport java.util.*;
public class NextPermutationSpaceOpt {
public static void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0) {
int j = nums.length - 1;
while (nums[j] <= nums[i]) j--;
swap(nums, i, j);
}
reverse(nums, i + 1, nums.length - 1);
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp;
}
private static void reverse(int[] nums, int start, int end) {
while (start < end) {
swap(nums, start++, end--);
}
}
// Driver code
public static void main(String[] args) {
int[] arr = {1,2,3};
nextPermutation(arr);
System.out.println(Arrays.toString(arr)); // Output: [1,3,2]
}
}int i = nums.length - 2;Start from second last index to find pivotwhile (i >= 0 && nums[i] >= nums[i + 1]) i--;Find first decreasing element from rightif (i >= 0)If pivot found, find element to swap withreverse(nums, i + 1, nums.length - 1);Reverse suffix in-place to get next permutation#include <bits/stdc++.h>
using namespace std;
void nextPermutation(vector<int>& nums) {
int i = (int)nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0) {
int j = (int)nums.size() - 1;
while (nums[j] <= nums[i]) j--;
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
int main() {
vector<int> arr = {1,2,3};
nextPermutation(arr);
for (int x : arr) cout << x << ' '; // Output: 1 3 2
cout << '\n';
return 0;
}int i = (int)nums.size() - 2;Start from second last element to find pivotwhile (i >= 0 && nums[i] >= nums[i + 1]) i--;Find first decreasing element from rightif (i >= 0)If pivot found, find element to swap withreverse(nums.begin() + i + 1, nums.end());Reverse suffix in-place to get next permutationfunction nextPermutation(nums) {
let i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
if (i >= 0) {
let j = nums.length - 1;
while (nums[j] <= nums[i]) j--;
[nums[i], nums[j]] = [nums[j], nums[i]];
}
let left = i + 1, right = nums.length - 1;
while (left < right) {
[nums[left], nums[right]] = [nums[right], nums[left]];
left++;
right--;
}
}
// Driver code
let arr = [1,2,3];
nextPermutation(arr);
console.log(arr); // Output: [1,3,2]let i = nums.length - 2;Start from second last index to find pivotwhile (i >= 0 && nums[i] >= nums[i + 1]) i--;Find first decreasing element from rightif (i >= 0)If pivot found, find element to swap withwhile (left < right)Reverse suffix in-place to get next permutationO(n)O(1)All operations are done in-place with linear scans and swaps.
This is the best practical approach to implement in interviews.
| Approach | Time | Space | Stack Risk | Reconstruct | Use In Interview |
|---|---|---|---|---|---|
| 1. Brute Force | O(n! * n log n) | O(n! * n) | Yes (deep recursion) | Yes | Mention only - never code |
| 2. Better Approach (Pivot and Swap) | O(n) | O(1) | No | N/A | Code this approach |
| 3. Space Optimized (In-place Reverse) | O(n) | O(1) | No | N/A | Code this approach (same as 2) |
How to Present
Step 1: Clarify the problem and constraints with the interviewer.Step 2: Describe the brute force approach to show understanding.Step 3: Explain the better approach using pivot and suffix reversal.Step 4: Code the optimal in-place solution carefully.Step 5: Test with edge cases and explain time/space complexity.
Time Allocation
What the Interviewer Tests
Interviewer tests your understanding of permutation ordering, ability to optimize from brute force to linear time, and skill in in-place array manipulation.
Common Follow-ups
- How to find previous permutation? → Reverse the logic to find first increasing element from right.
- Can you do this for strings? → Yes, same logic applies to character arrays.
When to Use
1) Asked for next or previous lexicographical permutation; 2) Input is a sequence or array; 3) Need in-place or efficient solution; 4) Problem involves rearranging elements to next order.
