
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:
- 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]
withk
reduced by the number of skipped sets.
- Consider remaining list
- Repeat the process:
- For subsequent digits, work with adjusting
n
ton-1
and recalculating the factorial till all digits are placed.
- For subsequent digits, work with adjusting
- 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
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 tosize!
. 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.
- 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
factorialValues
to store factorial values up tototal
and a listnumbers
containing integers from 1 tototal
. - The first loop calculates and fills the factorial values for each integer up to
total
increasing factorial calculations cumulatively and updatesnumbers
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
namedpermBuilder
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 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
fact
array holds factorials of integers from 0 up tolength - 1
. - The
elements
array 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 - 1
and populate thefact
array. Factorials are used to determine positions in the permutation sequence. - Initialize the
elements
array with char values starting from '1' tolength
.
- Calculate the factorials for numbers from 0 to
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.
- Subtract one from the
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.
- The
Return Permutation:
- Finalize the
permuted
string 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
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 currentsequence
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
toresult
and 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
production
to hold factorials of indices and a list calledelements
containing 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
position
by the factorial of the current index, then use this index to select the appropriate element fromelements
. - 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.
No comments yet.