
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 <= 91 <= 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:
- Recognize that the first number in the permutation is fixed every
(n-1)! times. For instance, ifn = 4, every set of six permutations (since3! = 6) starts with a fixed first number:- First six permutations start with '1'
- Next six start with '2', and so forth.
- Calculate how many complete sets of
(n-1)!permutations fit intok. 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.
- Remove the selected first digit from the list and reduce the problem:
- Consider remaining list
[2, 3, …, n]withkreduced by the number of skipped sets.
- Consider remaining list
- Repeat the process:
- For subsequent digits, work with adjusting
nton-1and recalculating the factorial till all digits are placed.
- For subsequent digits, work with adjusting
- This route focuses on constructing the required
kthpermutation 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
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
factorialValuesto store factorial calculations up tosize!. This helps in determining the position of each digit in the sequence. - Initializes another vector
availableNumbersthat 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
kis converted to zero-based for easier calculations within the loop structure. - A loop runs from
size-1down to zero. Inside the loop:- The index for the current digit to pick is determined by integer-dividing
kby the factorial of the current position. - The character at this index in
availableNumbersis appended to the resulting permutation string. - The selected character is removed from
availableNumbersto ensure it is not reused. kis then updated to the remainder of dividing it by the current factorial value.
- The index for the current digit to pick is determined by integer-dividing
- 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.
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
factorialValuesto store factorial values up tototaland a listnumberscontaining integers from 1 tototal. - The first loop calculates and fills the factorial values for each integer up to
totalincreasing factorial calculations cumulatively and updatesnumberslist with sequence values accordingly. - It then decrements
kthby one, adjusting from 1-based indexing to 0-based indexing used in programming. - A
StringBuildernamedpermBuilderis utilized to build the permutation string. In the succeeding loop:- The index for current digit of the permutation is determined by dividing
kthby the factorial of the remaining digits. kthis adjusted by subtracting the number of sequences skipped over.- The appropriate number is fetched and removed from
numbers, then appended topermBuilder.
- The index for current digit of the permutation is determined by dividing
- 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.
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
factarray holds factorials of integers from 0 up tolength - 1. - The
elementsarray stores characters representing numbers from '1' to the character equivalent oflength.
- The
Factorials and Initial Elements:
- Calculate the factorials for numbers from 0 to
length - 1and populate thefactarray. Factorials are used to determine positions in the permutation sequence. - Initialize the
elementsarray with char values starting from '1' tolength.
- Calculate the factorials for numbers from 0 to
Adjust Position:
- Subtract one from the
positionto convert it from a one-based index to a zero-based index, which simplifies calculations in zero-indexed arrays.
- Subtract one from the
Compute the Permutation:
- The
permutedarray, 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
elementsarray. - Adjust
positionfor the next iteration using modular arithmetic. - Use
memmoveto remove the element that has just been used to ensure it is not reused.
- The
Return Permutation:
- Finalize the
permutedstring by ensuring its termination and return it as the result.
- Finalize the
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.
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
sequencenumber 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-1down to 0:- Determine the position of the next number in the
numbersarray by dividing the currentsequencevalue 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
numberstoresultand remove that number fromnumbers.
- Determine the position of the next number in the
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.
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
productionto hold factorials of indices and a list calledelementscontaining string representations from '1' tosize. - 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
positionby the factorial of the current index, then use this index to select the appropriate element fromelements. - Update
positionby subtracting the contribution of the chosen element positioned at the current index. - Remove the used number from
elementsso 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.