Next Permutation

Updated on 01 July, 2025
Next Permutation header image

Problem Statement

The problem requires determining the next lexicographical permutation of a given array of integers. If we consider a "permutation" as any possible arrangement of an array's elements, the "next permutation" is specifically the arrangement that comes immediately after the current one when all permutations are considered in a sorted lexicographical order.

If the array in its current form is the highest permutation (meaning no greater permutation is possible), it should be reorganized into the lowest possible permutation (i.e., sorted in ascending order). This process must be achieved by modifying the array in place, adhering to the constraint of using no extra memory beyond what is constant to the duration of the algorithm.

Examples

Example 1

Input:

nums = [1,2,3]

Output:

[1,3,2]

Example 2

Input:

nums = [3,2,1]

Output:

[1,2,3]

Example 3

Input:

nums = [1,1,5]

Output:

[1,5,1]

Constraints

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

Approach and Intuition

The key to solving this problem lies in manipulating the sequence directly to achieve the next permutation with efficient handling of time and space complexity:

  1. Identify Decrease: Traverse from the end of the array to find the first pair (i, j) such that nums[i] < nums[j] where j = i + 1. This is the first decreasing element when viewed from the back of the array.

  2. Decide Pivot and Swap:

    • If such a pair (i, j) is found, it indicates that possibly a greater arrangement can be formed by altering the sequence from index i onwards.
    • Locate the largest index k from the end such that nums[k] > nums[i]. This identifies the element just greater than nums[i] to swap and ensure only the next permutation is achieved.
    • Swap elements nums[i] and nums[k].
  3. Rearrange for Next Sequence:

    • Reverse the sub-array from i + 1 to the end of the array. Reversing this sub-sequence guarantees the smallest lexicographical order of this sub-array, yielding the next permutation.
    • If no pair (i, j) was found in the first step, this means the entire array is non-increasing from end to start. Hence, simply reverse the entire array to reset it to the smallest permutation.

By following this method, the sequence transformation adheres to in-place memory usage, satisfying the constant extra memory constraint. The steps above effectively map to manipulating pointers and values within the existing array, providing a clear path from one permutation to the next in an optimal manner.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    void getNextPermutation(vector<int>& array) {
        int k = array.size() - 2;
        while (k >= 0 && array[k + 1] <= array[k]) {
            k--;
        }
        if (k >= 0) {
            int l = array.size() - 1;
            while (array[l] <= array[k]) {
                l--;
            }
            performSwap(array, k, l);
        }
        reverse(array.begin() + k + 1, array.end());
    }
    
private:
    void performSwap(vector<int>& array, int k, int l) {
        int tmp = array[k];
        array[k] = array[l];
        array[l] = tmp;
    }
};

The given C++ solution finds the next lexicographical permutation of a sequence of integers provided in a vector. Implementing this requires a few specific array manipulations:

  1. Identify the right-most character in the array that is smaller than its successor. This determines the pivot point around which reordering will occur.

  2. If a valid pivot is found, locate the smallest element after the pivot that is greater than the pivot itself. This step is critical as it helps determine which value should swap with the pivot to form the next greater permutation.

  3. Execute a swap between the pivot and the chosen successor element. This swap is central to forming a permutation that is the next largest configuration of the array's numbers.

  4. Finally, reverse the segment of the array that follows the pivot. This ensures the smallest possible configuration of the remaining numbers, solidifying the smallest next permutation.

Internally, the solution defines a helper function performSwap to encapsulate the logic of swapping two elements in the array. This contributes to cleaner and more maintainable code by segregating responsibilities within the class.

The code utilizes standard C++ library functions, such as vector manipulation, to perform operations like reversing a sub-part of the array, which is essential for obtaining the correct order of elements in the final permutation.

Overall, the solution effectively generates the next permutation by adhering to a set algorithm involving conditional checks and manipulations of the input array.

java
public class Solution {
    public void nextPermutation(int[] arr) {
        int index = arr.length - 2;
        while (index >= 0 && arr[index + 1] <= arr[index]) {
            index--;
        }
        if (index >= 0) {
            int swapIndex = arr.length - 1;
            while (arr[swapIndex] <= arr[index]) {
                swapIndex--;
            }
            exchange(arr, index, swapIndex);
        }
        reverseArray(arr, index + 1);
    }
    
    private void reverseArray(int[] arr, int start) {
        int left = start, right = arr.length - 1;
        while (left < right) {
            exchange(arr, left, right);
            left++;
            right--;
        }
    }
    
    private void exchange(int[] arr, int i, int j) {
        int placeholder = arr[i];
        arr[i] = arr[j];
        arr[j] = placeholder;
    }
}

The provided Java solution efficiently computes the next permutation of an array of integers that represents a number. Below is the breakdown of the code:

  1. Initialize index to the second last position of the array. Start traversing the array backwards to find the first pair where the current element is less than the next element. This is to locate the rightmost ascending order sequence breach.

  2. If such an index is found (i.e., the array isn't entirely in descending order), identify the smallest element from the end of the array which is greater than the element at index. Let's refer to this position as swapIndex.

  3. Swap the elements at index and swapIndex using the helper function exchange, which swaps the elements at two given array indices.

  4. After swapping, reverse the portion of the array from index + 1 to the end to convert the descending sequence into an ascending one, using the reverseArray helper function. This step ensures the smallest lexicographically larger permutation.

The functions exchange and reverseArray serve as utility methods:

  • exchange: Swaps the values of two specific array positions.
  • reverseArray: Reverses the segment of the array starting from the specified start index.

Overall, this efficient approach ensures the array transforms directly into its next permutation without needing to generate all possible permutations. The code handles edge cases, such as when the input array is sorted in descending order, by effectively reversing the array to provide the smallest possible permutation.

c
void exchangeElements(int* array, int idx1, int idx2) {
    int temp = array[idx1];
    array[idx1] = array[idx2];
    array[idx2] = temp;
}
    
void reverseArray(int* array, int start, int length) {
    int left = start, right = length - 1;
    while (left < right) {
        exchangeElements(array, left, right);
        left++;
        right--;
    }
}
    
void nextLexicographicalPermutation(int* array, int length) {
    int k = length - 2;
    while (k >= 0 && array[k + 1] <= array[k]) {
        k--;
    }
    if (k >= 0) {
        int l = length - 1;
        while (array[l] <= array[k]) {
            l--;
        }
        exchangeElements(array, k, l);
    }
    reverseArray(array, k + 1, length);
}

To rearrange a given array to its next lexicographically greater permutation, follow these steps:

  1. Identify two sequential indices k and l where k is the last index in the array where the subsequent value is greater (array[k] < array[k + 1]). If no such position exists from right to left, the given permutation is the highest permutation.

  2. Find the rightmost value at index l such that array[l] > array[k]. This step ensures that swapping these values positions the array closer to the next permutation.

  3. Swap the values at index k and l. This step will form a new sequence where the portion to the right of k needs to be reversed to form the smallest lexicographical sequence from that point.

  4. Reverse the sub-array from index k + 1 till the end of the array. This reversal guarantees the smallest lexicographical sequence for the portion right of k.

This procedure results in transforming an array array of length length into its next permutation. Utilize helper functions to manage common operations such as element swapping (exchangeElements) and array segment reversal (reverseArray):

  • The exchangeElements function swaps two elements in the array.
  • The reverseArray function reverses a segment of the array starting from a given index up to another index.

These operations together adjust the provided array in-place to represent its next permutation sequence efficiently.

js
var findNextPermutation = function (elements) {
    let index = elements.length - 2;
    while (index >= 0 && elements[index + 1] <= elements[index]) {
        index--;
    }
    if (index >= 0) {
        let k = elements.length - 1;
        while (elements[k] <= elements[index]) {
            k--;
        }
        exchange(elements, index, k);
    }
    reverseSection(elements, index + 1);
    function reverseSection(elements, start) {
        let left = start,
            right = elements.length - 1;
        while (left < right) {
            exchange(elements, left, right);
            left++;
            right--;
        }
    }
    function exchange(elements, i, j) {
        let tmp = elements[i];
        elements[i] = elements[j];
        elements[j] = tmp;
    }
};

The JavaScript solution provided implements the function findNextPermutation that generates the next lexicographically greater permutation of a list of integers. If the function doesn't find a greater permutation, the sequence is rearranged into its lowest possible order. This algorithm is beneficial for problems related to rearranging sequences in a specific order.

Follow these steps to understand the workflow of the code:

  1. Initialize index to the second-to-last position in the elements array.
  2. Move index leftwards until an element found that is less than its next right neighbor, identifying a position where the current sequence order can be increased.
  3. If such an index exists (i.e., index >= 0):
    • Identify the rightmost element (from the end of the array back to index) that is greater than the element at index. This is for swapping to find the next permutation.
    • Use the exchange function to swap the elements at index and the identified element k to make a higher permutation.
  4. Regardless of finding an index, the sub-array starting from the position right after the index is reversed. This step ensures that the sub-array is in the lowest possible order, which is a critical step to form the next minimum higher permutation or to reset if the current permutation is the highest.

The reverseSection and exchange are helper functions:

  • reverseSection reverses the elements of the array from a starting index to the end.
  • exchange swaps two elements in the array, using a temporary variable to facilitate the swap.

This implementation ensures an efficient transition to the next permutation with a time complexity closely approximating O(n), where n is the number of elements in the list. This makes the algorithm suitable for time-sensitive applications needing to generate permutations in lexicographical order.

python
class Solution:
    def findNextPermutation(self, elements):
        idx = len(elements) - 2
        while idx >= 0 and elements[idx + 1] <= elements[idx]:
            idx -= 1
        if idx >= 0:
            pivot = len(elements) - 1
            while elements[pivot] <= elements[idx]:
                pivot -= 1
            self.exchange(elements, idx, pivot)
        self.invert(elements, idx + 1)
    
    def invert(self, elements, begin):
        start, end = begin, len(elements) - 1
        while start < end:
            self.exchange(elements, start, end)
            start += 1
            end -= 1
    
    def exchange(self, elements, first, second):
        buffer = elements[first]
        elements[first] = elements[second]
        elements[second] = buffer

The Next Permutation problem aims to find the next lexicographic permutation of a list of integers if possible, or reorder the list in ascending order if the given list is already the highest permutation.

Here is a compact overview of the provided Python3 solution implementation:

  • Main Function - findNextPermutation:

    • Initializes by identifying the rightmost element (idx) which is smaller than its next element to find the first decreasing element when traversed from the end.
    • If such an element is found (i.e., idx is non-negative), locate the furthest right element (pivot) that is greater than this indexed element to prepare for a swap; this is vital to get the next permutation.
    • Swaps the identified elements, then reverses the order of the elements following idx to get the smallest possible sequence for the next permutation.
  • Helper Functions:

    • invert: Reverses a sublist from a specified start index to the end of the list.
    • exchange: A utility to swap two elements in a list based on their indices, utilizing a buffer for the exchange.

The approach effectively locates the sequence where the order of elements needs to be incremented to the next permutation or reset. If the elements are initially in descending order, the solution reorders them to the smallest (ascending) permutation. When a specific order must be adjusted, it identifies the minimal changes required, ensuring efficient transition to the next permutation with optimal swaps and a single reversal operation.

Comments

No comments yet.