A permutation of an array of integers is an arrangement of its members into a sequence or linear order.
arr = [1,2,3]
, the following are all the permutations of arr
: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1]
.The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).
arr = [1,2,3]
is [1,3,2]
.arr = [2,3,1]
is [3,1,2]
.arr = [3,2,1]
is [1,2,3]
because [3,2,1]
does not have a lexicographical larger rearrangement.Given an array of integers nums
, find the next permutation of nums
. The replacement must be in place and use only constant extra memory. Give the optimal solution. Explain Big(O) run-time. Explain Big(O) space usage. Break down edge cases.
Example:
nums = [1,2,3]
should produce [1,3,2]
nums = [3,2,1]
should produce [1,2,3]
nums = [1,1,5]
should produce [1,5,1]
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the next permutation is about trying every possible ordering. We explore all arrangements of the given numbers until we find one that is larger than the current order but still the smallest possible one.
Here's how the algorithm would work step-by-step:
def next_permutation_brute_force(numbers):
import itertools
original_numbers = numbers.copy()
all_permutations = list(itertools.permutations(numbers))
larger_permutations = []
for permutation in all_permutations:
# Compare the current permutation with the original
if permutation > tuple(original_numbers):
larger_permutations.append(list(permutation))
if not larger_permutations:
# If no larger permutation exists, return sorted array
numbers.sort()
return numbers
else:
# Find the smallest permutation among the larger ones
next_permutation_candidate = larger_permutations[0]
for permutation in larger_permutations:
if permutation < next_permutation_candidate:
next_permutation_candidate = permutation
return next_permutation_candidate
The goal is to rearrange a set of numbers into the next arrangement that's bigger than the current one. We want to do this efficiently, without checking every possible order. Instead of brute force, we locate a strategic spot to make a small change, then optimize the rest.
Here's how the algorithm would work step-by-step:
def next_permutation(numbers):
index_to_swap = -1
for i in range(len(numbers) - 2, -1, -1):
if numbers[i] < numbers[i+1]:
index_to_swap = i
break
# If no such index exists, reverse the array
if index_to_swap == -1:
numbers.reverse()
return
index_to_find_replacement = -1
# Find the smallest number to the right of index_to_swap
# that is still greater than numbers[index_to_swap]
for i in range(len(numbers) - 1, index_to_swap, -1):
if numbers[i] > numbers[index_to_swap]:
index_to_find_replacement = i
break
# Swap the numbers
numbers[index_to_swap], numbers[index_to_find_replacement] = numbers[index_to_find_replacement], numbers[index_to_swap]
# Reverse the sub-array to the right of index_to_swap
left_index = index_to_swap + 1
right_index = len(numbers) - 1
# Reverse the portion of the array after the swapped element
while left_index < right_index:
numbers[left_index], numbers[right_index] = numbers[right_index], numbers[left_index]
left_index += 1
right_index -= 1
Case | How to Handle |
---|---|
Null or empty input array | Return immediately or throw an IllegalArgumentException since there's no permutation to compute. |
Array with one element | Return immediately as the array is already in its only possible permutation. |
Array is already in descending order (largest permutation) | Reverse the array to get the smallest (ascending) permutation. |
Array contains duplicate numbers | The algorithm should correctly handle duplicates during the swap and reverse operations, finding the next lexicographical permutation even with duplicates. |
Array contains all identical numbers | The algorithm should correctly identify that no greater permutation is possible and reverse the array into ascending order. |
Array with very large numbers potentially causing integer overflow during comparisons | Use appropriate data types to avoid overflow and ensure comparisons are accurate, considering potential constraints in the problem description. |
Maximum sized input array (performance considerations) | The algorithm has a time complexity of O(n) which is efficient enough, but profiling large inputs can confirm performance. |
Array contains negative numbers | The algorithm will correctly sort the negative numbers and find the next permutation in lexicographical order. |