Next Permutation

Hero Image

Problem Overview

In this article, we will delve into the "Next Permutation" problem on LeetCode, a classic problem in the realm of arrays and permutations. The problem prompts us to rearrange numbers into the lexicographically next greater permutation of numbers. If such an arrangement is not possible, it must rearrange it as the lowest possible order (sorted in ascending order). This challenge tests your understanding of permutations, arrays, and algorithms, while honing problem-solving skills crucial for technical interviews.

Understanding the Problem

To comprehend the problem, consider the following score: given a sequence, or permutation, of numbers, generate the next permutation lexicographically. For instance, the sequence [1, 2, 3] has permutations such as [1, 3, 2], [2, 1, 3], etc. The task is to derive each subsequent permutation, and if you reach the last permutation, start with the first permutation.

Example:

  • Input: [1, 2, 3]

  • Output: [1, 3, 2]

  • Input: [3, 2, 1]

  • Output: [1, 2, 3]

Key DSA Concepts and Theory

Permutations

Permutations refer to all possible arrangements of a set of numbers. For example, given numbers [1, 2, 3], the permutations are 123, 132, 213, 231, 312, 321. Our task is to find the next arrangement after a given one — the next permutation in lexicographic order.

Lexicographic Order

This defines the arrangement similar to dictionary order applied to sequences of elements. For numbers in increasing order, the lexicographically next sequence is sought.

Algorithm Theory

This problem can be effectively solved using a single-pass algorithm. The trick lies in understanding how to manipulate the array slightly to get the next larger permutation without generating all possibilities.

Solution Approach

To find the next permutation, we need to perform the following steps:

  1. Identify the Longest Non-Increasing Suffix:

    • Traverse the array from end to start and find the first pair where nums[i] < nums[i + 1]. This transition marks the end of the current permutation prefix.
  2. Find Successor to the Pivot:

    • If such an index was found, find the smallest element in the suffix that is larger than nums[i], swap it with nums[i].
  3. Reverse the Suffix:

    • Finally, reverse the order of elements from the i+1 position onward to get the smallest lexicographic order of the suffix again.

C++ Code Example

#include <algorithm>
#include <vector>

void nextPermutation(std::vector<int>& nums) {
    int i = nums.size() - 2;
    // Step 1: Find the first decreasing element from the end
    while (i >= 0 && nums[i] >= nums[i + 1]) {
        i--;
    }
    // Step 2: If the entire array is non-increasing from the end, reverse it
    if (i >= 0) {
        int j = nums.size() - 1;
        while (nums[j] <= nums[i]) {
            j--;
        }
        // Swap the found elements
        std::swap(nums[i], nums[j]);
    }
    // Step 3: Reverse the suffix
    std::reverse(nums.begin() + i + 1, nums.end());
}

Java Code Example

import java.util.Arrays;

public class NextPermutation {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        // Step 1: Find the first decreasing element from the end
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        // Step 2: If such an element exists, swap it with the smallest element on the right larger than it
        if (i >= 0) {
            int j = nums.length - 1;
            while (nums[j] <= nums[i]) {
                j--;
            }
            // Swap the elements
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
        // Step 3: Reverse the portion of the array from i+1 onward
        int start = i + 1;
        int end = nums.length - 1;
        while (start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

Time and Space Complexity Analysis

  • Time Complexity: The algorithm runs in O(n) time because each step involves at most two linear traversals of the array — one to find the pivot, and another to swap or reverse the sequence.

  • Space Complexity: O(1). The transformation is done in-place, requiring no additional space.

Common Mistakes to Avoid

  1. Handling the Entire Non-Increasing Sequence:

    • Ensure proper identification of the longest non-increasing suffix. Forgetting to handle this can result in incorrect results.
  2. In-Place Reversing After Swap:

    • Many mistakes arise from incorrect reversing of the suffix after swapping the pivot element, which is crucial for maintaining lexicographic order.

Similar Problems on LeetCode

For further practice with permutations and array manipulations, consider these related problems:

  • Permutations: LeetCode 46
  • Permutations II: LeetCode 47
  • Kth Permutation Sequence: LeetCode 60

Additional Resources and References

  • Permutations in Mathematics: Wikipedia on Permutations
  • Detailed Video Explanation: Search for "next permutation algorithm" on platforms like YouTube.
  • Other References: Look for competitive programming tutorials that deep dive into permutations and combinatory algorithms.