Permutation Sequence

Updated on 01 July, 2025
Permutation Sequence header image

Problem Statement

The task involves generating permutations for a set of numbers starting from 1 up to n and identifying a specific permutation sequence. From the total number of possible unique permutations, which amount to n! (factorial of n), the challenge is to find and return the permutation that sits at position k. The sequence of permutations is created in a lexicographical order, so each list is a systematized rearrangement of the numbers [1, 2, 3, ..., n].

For example, if n = 3, there are 3! = 6 permutations. Listing these from the first to the sixth in order will give: "123", "132", "213", "231", "312", and "321". If you are tasked to find the third permutation (k = 3), the correct output would be the sequence "213".

Examples

Example 1

Input:

n = 3, k = 3

Output:

"213"

Example 2

Input:

n = 4, k = 9

Output:

"2314"

Example 3

Input:

n = 3, k = 1

Output:

"123"

Constraints

  • 1 <= n <= 9
  • 1 <= k <= n!

Approach and Intuition

Given the problem constraints, the brute force approach of generating all n! permutations and then selecting the k-th one can be computationally costly, especially as n reaches its upper limit. Instead, the solution can be approached more efficiently using a placement and reduction strategy based on understanding the structure of permutations:

  1. Recognize that the first number in the permutation is fixed every (n-1)! times. For instance, if n = 4, every set of six permutations (since 3! = 6) starts with a fixed first number:
    • First six permutations start with '1'
    • Next six start with '2', and so forth.
  2. Calculate how many complete sets of (n-1)! permutations fit into k. This tells us the first digit of our target permutation:
    • loc = (k-1) // factorial(n-1)
    • This locational index helps select the first digit from our list.
  3. Remove the selected first digit from the list and reduce the problem:
    • Consider remaining list [2, 3, …, n] with k reduced by the number of skipped sets.
  4. Repeat the process:
    • For subsequent digits, work with adjusting n to n-1 and recalculating the factorial till all digits are placed.
  5. This route focuses on constructing the required kth permutation directly rather than generating all permutations.

With careful iteration and updating of the k value, this approach achieves the target permutation in a linear computational time relative to n, proving much more efficient than generating all permutations upfront. In practical terms, for maximum constraints (with n = 9), this approach is feasible and quick due to factorial scaling and mathematical operations used to directly pinpoint each character of the desired permutation sequence.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    string kthPermutation(int size, int k) {
        vector<int> factorialValues(size); // Store factorial values
        vector<char> availableNumbers;     // Available digits
        factorialValues[0] = 1;            // Initialize factorials starting with 0!
        availableNumbers.push_back('1');   // Init the list of numbers from '1' to 'n'
            
        for (int i = 1; i < size; ++i) {
            factorialValues[i] = factorialValues[i - 1] * i;
            availableNumbers.push_back(char('1' + i));
        }
            
        --k;  // Convert k to 0-based index
        string permutation = "";
        for (int i = size - 1; i >= 0; --i) {
            int index = k / factorialValues[i];
            k %= factorialValues[i];
            permutation += availableNumbers[index];
            availableNumbers.erase(availableNumbers.begin() + index);
        }
        return permutation;
    }
};

The given C++ solution determines the k-th permutation sequence of numbers from 1 to size. Here's a summary of how the solution achieves this:

  • Initializes a vector factorialValues to store factorial calculations up to size!. This helps in determining the position of each digit in the sequence.
  • Initializes another vector availableNumbers that lists all characters from '1' to 'n' representing available digits for forming permutations.
  • The factorials are calculated iteratively and stored. Each number from '1' to 'size' is added to availableNumbers.
  • The sequence index k is converted to zero-based for easier calculations within the loop structure.
  • A loop runs from size-1 down to zero. Inside the loop:
    • The index for the current digit to pick is determined by integer-dividing k by the factorial of the current position.
    • The character at this index in availableNumbers is appended to the resulting permutation string.
    • The selected character is removed from availableNumbers to ensure it is not reused.
    • k is then updated to the remainder of dividing it by the current factorial value.
  • After exiting the loop, the complete permutation sequence as a string is returned.

This efficient approach leverages factorial-based indexing to directly identify positions in the permutation sequence without generating all possible permutations.

java
class Solution {
    public String findKthPermutation(int total, int kth) {
        int[] factorialValues = new int[total];
        List<Integer> numbers = new ArrayList<Integer>() {{
            add(1);
        }};
    
        factorialValues[0] = 1;
        for (int i = 1; i < total; ++i) {
            factorialValues[i] = factorialValues[i - 1] * i;
            numbers.add(i + 1);
        }
    
        kth--;
    
        StringBuilder permBuilder = new StringBuilder();
        for (int i = total - 1; i >= 0; --i) {
            int index = kth / factorialValues[i];
            kth -= index * factorialValues[i];
    
            permBuilder.append(numbers.get(index));
            numbers.remove(index);
        }
        return permBuilder.toString();
    }
}

The Java solution provided finds the kth permutation sequence of numbers given a total number of elements. Here's a concise explanation of how the code achieves this:

  • Initializes an array factorialValues to store factorial values up to total and a list numbers containing integers from 1 to total.
  • The first loop calculates and fills the factorial values for each integer up to total increasing factorial calculations cumulatively and updates numbers list with sequence values accordingly.
  • It then decrements kth by one, adjusting from 1-based indexing to 0-based indexing used in programming.
  • A StringBuilder named permBuilder is utilized to build the permutation string. In the succeeding loop:
    • The index for current digit of the permutation is determined by dividing kth by the factorial of the remaining digits.
    • kth is adjusted by subtracting the number of sequences skipped over.
    • The appropriate number is fetched and removed from numbers, then appended to permBuilder.
  • Finally, the assembled string representing the kth permutation sequence is returned.

This approach involves iterative calculations based on factorial values, effectively pinpointing positions in a lexicographical arrangement, making it efficient for finding specific sequence orders without generating all permutations.

c
char *findPermutation(int length, int position) {
    int fact[length];                                         // Store factorials
    char *elements = malloc((length + 1) * sizeof(char));     // Element storage
    elements[length] = '\0';                                  // String termination
    int idx;
    fact[0] = 1;                                             // Factorial base initialization
    elements[0] = '1';                                        // Initialize elements
    for (idx = 1; idx < length; ++idx) {
        fact[idx] = fact[idx - 1] * idx;
        elements[idx] = (idx + 1) + '0';
    }
    position--;                                               // Adjust position to zero-based index
    char *permuted = malloc((length + 1) * sizeof(char));     // Permuted result
    permuted[length] = '\0';                                  // Terminate string
    for (int pos = length - 1, i = 0; pos >= 0; --pos, i++) {
        int index = position / fact[pos];
        position -= index * fact[pos];
        permuted[i] = elements[index];
        // Remove used elements by shifting
        memmove(&elements[index], &elements[index + 1], pos - index);
    }
    return permuted;
}

The provided C code implements a function that determines the position-th permutation of a sequence of numbers from 1 to length. Here's a breakdown of how the function findPermutation operates:

  • Array Initialization:

    • The fact array holds factorials of integers from 0 up to length - 1.
    • The elements array stores characters representing numbers from '1' to the character equivalent of length.
  • Factorials and Initial Elements:

    • Calculate the factorials for numbers from 0 to length - 1 and populate the fact array. Factorials are used to determine positions in the permutation sequence.
    • Initialize the elements array with char values starting from '1' to length.
  • Adjust Position:

    • Subtract one from the position to convert it from a one-based index to a zero-based index, which simplifies calculations in zero-indexed arrays.
  • Compute the Permutation:

    • The permuted array, which will hold the result, is allocated and initialized.
    • Loop over each position from last to first, determine the index for the current position using integer division by the corresponding factorial. This index helps pick the right current element from the elements array.
    • Adjust position for the next iteration using modular arithmetic.
    • Use memmove to remove the element that has just been used to ensure it is not reused.
  • Return Permutation:

    • Finalize the permuted string by ensuring its termination and return it as the result.

This function is efficient in generating specific permutations without generating all possible permutations upfront, making it suited for scenarios where only one specific permutation sequence out of many is needed.

js
var permutationSequence = function (total, sequence) {
    let factorials = new Array(total); // Calculate factorials
    let numbers = ["1"]; // Initial number setup
    // Calculate all required factorials and fill number sequence
    factorials[0] = 1;
    for (let index = 1; index < total; ++index) {
        factorials[index] = factorials[index - 1] * index;
        numbers.push((index + 1).toString());
    }
    // Adjust sequence to be zero-indexed
    --sequence;
    // Generate permutation
    let result = "";
    for (let index = total - 1; index >= 0; --index) {
        let position = Math.floor(sequence / factorials[index]);
        sequence -= position * factorials[index];
        result += numbers[position];
        numbers.splice(position, 1);
    }
    return result;
};

The JavaScript function, permutationSequence, effectively computes the nth permutation of a sequence made up of integers starting from 1 up to a given total. The process deployed here leverages factorials to determine the position of each number in the required permutation sequence efficiently. Below is a summary of how the solution operates:

  • Calculate factorials for all integers from 0 up to the given total and store these in an array, factorials. Simultaneously, construct an array, numbers, containing string representations of these integers.

  • Convert the input sequence number from a 1-based index to a 0-based index by reducing it by one. This adjusts the sequence query to fit zero-indexed programming common in many languages including JavaScript.

  • Initialize an empty string, result, which will be built up to form the desired permutation.

  • Iterate in reverse from total-1 down to 0:

    • Determine the position of the next number in the numbers array by dividing the current sequence value by the factorial of the current index.
    • Subtract the contribution of the chosen number from sequence, narrowing down the next potential number.
    • Append the number at the found position from numbers to result and remove that number from numbers.
  • Finally, the function returns result, which now holds the nth permutation sequence, constructed accurately according to the mathematical properties of permutations and factorials.

This method ensures a direct computation without the need for recursively generating all permutation options, thus being efficient and suitable for large values of total and sequence. The usage of JavaScript-specific features like Array operations (e.g., push, splice) and Math.floor for division rounding integrates well with JavaScript's capabilities to manage lists and numerical calculations.

python
class Solution:
    def calculatePermutation(self, size: int, position: int) -> str:
        production = [1]
        elements = ["1"]
        for j in range(1, size):
            production.append(production[j - 1] * j)
            elements.append(str(j + 1))
    
        position -= 1
    
        permutation = []
        for j in range(size - 1, -1, -1):
            index = position // production[j]
            position -= index * production[j]
    
            permutation.append(elements[index])
            del elements[index]
    
        return "".join(permutation)

This Python solution implements a method to determine the k-th permutation sequence of the first n natural numbers. The function calculatePermutation takes two parameters—size, which represents the total number of elements in the sequence, and position, which specifies the desired permutation position.

  • The function initializes a list called production to hold factorials of indices and a list called elements containing string representations from '1' to size.
  • Adjust for zero-indexing by subtracting one from position.
  • Iterate through each position in decreasing order to determine which number should be placed at each location in the resulting permutation string.
  • Calculate the index for the current position by integer division of position by the factorial of the current index, then use this index to select the appropriate element from elements.
  • Update position by subtracting the contribution of the chosen element positioned at the current index.
  • Remove the used number from elements so that it is not reused in subsequent positions.
  • Finally, join all selected numbers in order to form the desired permutation string.

This method efficiently computes the result by systematically reducing the problem size, leveraging factorial calculations to help determine the placement of each number in the permutation sequence.

Comments

No comments yet.