Given two integers n and k, find the k-th permutation sequence of the first n natural numbers arranged in lexicographical order. Return the answer as a string.
Examples:
Input: n = 4, k = 3
Output: 1324
Explanation: The permutations in lexicographical order are 1234, 1243, 1324, ..., so the 3rd permutation is 1324.Input: n = 3, k = 5
Output: 312
Explanation: The permutations in lexicographical order are 123, 132, 213, 231, 312, 321, so the 5th permutation is 312.
Table of Content
[Naive Approach] Generate All Permutations - O(n! × n) Time and O(n!) Space
The idea is to generate all possible permutations of numbers. Store all permutations in a list, sort them lexicographically and return the k-th permutation.
- Create a string containing numbers from 1 to n.
- Generate all permutations recursively and store every permutation in a list.
- Sort the list lexicographically and return the (k - 1) index permutation.
#include <bits/stdc++.h>
using namespace std;
// Function to generate all permutations
void generate(string &s, int idx,
vector<string> &res) {
// Base case
if (idx == s.length()) {
res.push_back(s);
return;
}
// Generate all possible permutations
for (int i = idx; i < s.length(); i++) {
// Swap characters
swap(s[idx], s[i]);
generate(s, idx + 1, res);
// Backtrack
swap(s[idx], s[i]);
}
}
string kthPermutation(int n, int k) {
string s = "";
// Create string "123...n"
for (int i = 1; i <= n; i++) {
s += to_string(i);
}
vector<string> res;
// Generate all permutations
generate(s, 0, res);
// Sort permutations lexicographically
sort(res.begin(), res.end());
return res[k - 1];
}
int main() {
int n = 3, k = 5;
cout << kthPermutation(n, k);
return 0;
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class GFG {
// Function to generate all permutations
static void generate(StringBuilder s, int idx,
List<String> res) {
// Base case
if (idx == s.length()) {
res.add(s.toString());
return;
}
// Generate all possible permutations
for (int i = idx; i < s.length(); i++) {
// Swap characters
char temp = s.charAt(idx);
s.setCharAt(idx, s.charAt(i));
s.setCharAt(i, temp);
generate(s, idx + 1, res);
// Backtrack
temp = s.charAt(idx);
s.setCharAt(idx, s.charAt(i));
s.setCharAt(i, temp);
}
}
static String kthPermutation(int n, int k) {
StringBuilder s = new StringBuilder();
// Create string "123...n"
for (int i = 1; i <= n; i++) {
s.append(i);
}
List<String> res = new ArrayList<>();
// Generate all permutations
generate(s, 0, res);
// Sort permutations lexicographically
Collections.sort(res);
return res.get(k - 1);
}
public static void main(String[] args) {
int n = 3, k = 5;
System.out.println(kthPermutation(n, k));
}
}
# Function to generate all permutations
def generate(s, idx, res):
# Base case
if idx == len(s):
res.append("".join(s))
return
# Generate all possible permutations
for i in range(idx, len(s)):
# Swap characters
s[idx], s[i] = s[i], s[idx]
generate(s, idx + 1, res)
# Backtrack
s[idx], s[i] = s[i], s[idx]
def kthPermutation(n, k):
s = []
# Create string "123...n"
for i in range(1, n + 1):
s.append(str(i))
res = []
# Generate all permutations
generate(s, 0, res)
# Sort permutations lexicographically
res.sort()
return res[k - 1]
if __name__ == "__main__":
n, k = 3, 5
print(kthPermutation(n, k))
using System;
using System.Collections.Generic;
class Program {
// Function to generate all permutations
static void generate(char[] s, int idx,
List<string> res) {
// Base case
if (idx == s.Length) {
res.Add(new string(s));
return;
}
// Generate all possible permutations
for (int i = idx; i < s.Length; i++) {
// Swap characters
char temp = s[idx];
s[idx] = s[i];
s[i] = temp;
generate(s, idx + 1, res);
// Backtrack
temp = s[idx];
s[idx] = s[i];
s[i] = temp;
}
}
static string kthPermutation(int n, int k) {
string s = "";
// Create string "123...n"
for (int i = 1; i <= n; i++) {
s += i.ToString();
}
List<string> res = new List<string>();
// Generate all permutations
generate(s.ToCharArray(), 0, res);
// Sort permutations lexicographically
res.Sort();
return res[k - 1];
}
static void Main() {
int n = 3, k = 5;
Console.WriteLine(kthPermutation(n, k));
}
}
// Function to generate all permutations
function generate(s, idx, res) {
// Base case
if (idx === s.length) {
res.push(s.join(""));
return;
}
// Generate all possible permutations
for (let i = idx; i < s.length; i++) {
// Swap characters
[s[idx], s[i]] = [s[i], s[idx]];
generate(s, idx + 1, res);
// Backtrack
[s[idx], s[i]] = [s[i], s[idx]];
}
}
function kthPermutation(n, k) {
let s = [];
// Create string "123...n"
for (let i = 1; i <= n; i++) {
s.push(i.toString());
}
let res = [];
// Generate all permutations
generate(s, 0, res);
// Sort permutations lexicographically
res.sort();
// Return k-th permutation
return res[k - 1];
}
// Drive code
let n = 3, k = 5;
console.log(kthPermutation(n, k));
Output
312
[Expected Approach] Factorial Number System - O(n²) Time and O(n) Space
The idea is based on the observation that in all permutations of n numbers, each number appears in the first position exactly (n - 1)! times. Hence, the first digit of the k-th permutation can be directly determined using: index = k / (n - 1)!.
Once the digit is selected, it is removed from the list of available digits since it cannot be reused. The problem then reduces to finding the permutation of the remaining n - 1 digits.
Next, update k as k = k % (n - 1)! to focus only on the remaining block of permutations. This process is repeated for each position until all digits are selected.
- Precompute factorials in an array fact[].
- Create a nums[] array to track used digits, where 0 indicates unused and 1 indicates used.
- Convert k into 0-based indexing by doing k = k - 1.
- Compute the size of one permutation block using fact[n - 1].
- Find the position using c = k / fact[n - 1] + 1, which determines the next unused digit to be selected.
- Traverse all digits and count only those that are unused.
- When the count reaches c, select that digit, mark it as used, and append it to the result.
- Update k = k % fact[n - 1].
- Repeat the same process for the remaining positions until all digits are selected.
Consider n = 3 and k = 5, initially available numbers are [1, 2, 3], after converting k into 0- based indexing k = 4, and the factorial values are 0! = 1, 1! = 1, and 2! = 2.
Step 1: Find the First Digit
- Remaining numbers: [1, 2, 3], block size: (3 - 1)! = 2! = 2
- Find index using: index = 4 / 2 = 2 . So, digit at index 2 is 3.
- Answer becomes "3", remove 3 from available numbers -> [1, 2], and update: k = 4 % 2 = 0
Step 2: Find the Second Digit
- Remaining numbers: [1, 2], block size: (2 - 1)! = 1! = 1
- Find index using: index = 0 / 1 = 0. So, digit at index 0 is 1.
- Answer becomes "31", remove 1 from available numbers -> [2], and update: k = 0 % 1 = 0
Step 3: Find the Last Digit
- Only one number is left: [2]
- Add 2 to the answer
Final answer becomes: "312"
#include <bits/stdc++.h>
using namespace std;
// Function to solve recursively
string solve(int n, int k,
vector<int> &fact,
vector<int> &nums) {
// Base case
if (n == 0) {
return "";
}
// Find which unused digit should come next
int c = k / fact[n - 1] + 1;
string str = "";
// Traverse all digits
for (int i = 0; i < nums.size(); i++) {
// Count only unused digits
c -= (nums[i] == 0 ? 1 : 0);
// If c becomes 0, select this digit
if (c == 0 && nums[i] == 0) {
// Mark digit as used
nums[i] = 1;
// Add digit to answer
str += to_string(i + 1);
break;
}
}
// Recursively solve for remaining digits
return str + solve(n - 1,
k % fact[n - 1],
fact, nums);
}
string kthPermutation(int n, int k) {
// Create factorial array
vector<int> fact(n + 1, 1);
for (int i = 1; i <= n; i++) {
fact[i] = i * fact[i - 1];
}
// Array to track used digits
vector<int> nums(n, 0);
// Convert k into 0-based indexing
k--;
// Find kth permutation
return solve(n, k, fact, nums);
}
int main() {
int n = 3;
int k = 5;
cout << kthPermutation(n, k);
return 0;
}
import java.util.Arrays;
public class GFG {
public static String solve(int n, int k,
int fact[], int nums[]) {
// Base case
if (n == 0) {
return "";
}
// Find which unused digit should come next
int c = k / fact[n - 1] + 1;
String str = "";
// Traverse all digits
for (int i = 0; i < nums.length; i++) {
// Count only unused digits
c -= (nums[i] == 0 ? 1 : 0);
// If c becomes 0, select this digit
if (c == 0 && nums[i] == 0) {
// Mark digit as used
nums[i] = 1;
// Add digit to answer
str += String.valueOf(i + 1);
break;
}
}
// Recursively solve for remaining digits
return str + solve(n - 1,
k % fact[n - 1],
fact, nums);
}
public static String kthPermutation(int n, int k) {
// Create factorial array
int fact[] = new int[n + 1];
Arrays.fill(fact, 1);
for (int i = 1; i <= n; i++) {
fact[i] = i * fact[i - 1];
}
// Array to track used digits
int nums[] = new int[n];
// Convert k into 0-based indexing
k--;
// Find kth permutation
return solve(n, k, fact, nums);
}
public static void main(String[] args) {
int n = 3;
int k = 5;
System.out.println(kthPermutation(n, k));
}
}
# Function to solve recursively
def solve(n, k, fact, nums):
# Base case
if n == 0:
return ""
# Find which unused digit should come next
c = k // fact[n - 1] + 1
str1 = ""
# Traverse all digits
for i in range(len(nums)):
# Count only unused digits
c -= (1 if nums[i] == 0 else 0)
# If c becomes 0, select this digit
if c == 0 and nums[i] == 0:
# Mark digit as used
nums[i] = 1
# Add digit to answer
str1 += str(i + 1)
break
# Recursively solve for remaining digits
return str1 + solve(n - 1,
k % fact[n - 1],
fact, nums)
def kthPermutation(n, k):
# Create factorial array
fact = [1] * (n + 1)
for i in range(1, n + 1):
fact[i] = i * fact[i - 1]
# Array to track used digits
nums = [0] * n
# Convert k into 0-based indexing
k -= 1
# Find kth permutation
return solve(n, k, fact, nums)
if __name__ == "__main__":
n = 3
k = 5
print(kthPermutation(n, k))
using System;
class GFG {
// Function to solve recursively
static string solve(int n, int k,
int[] fact, int[] nums) {
// Base case
if (n == 0) {
return "";
}
// Find which unused digit should come next
int c = k / fact[n - 1] + 1;
string str = "";
// Traverse all digits
for (int i = 0; i < nums.Length; i++) {
// Count only unused digits
c -= (nums[i] == 0 ? 1 : 0);
// If c becomes 0, select this digit
if (c == 0 && nums[i] == 0) {
// Mark digit as used
nums[i] = 1;
// Add digit to answer
str += (i + 1).ToString();
break;
}
}
// Recursively solve for remaining digits
return str + solve(n - 1,
k % fact[n - 1],
fact, nums);
}
static string kthPermutation(int n, int k) {
// Create factorial array
int[] fact = new int[n + 1];
Array.Fill(fact, 1);
for (int i = 1; i <= n; i++) {
fact[i] = i * fact[i - 1];
}
// Array to track used digits
int[] nums = new int[n];
// Convert k into 0-based indexing
k--;
// Find kth permutation
return solve(n, k, fact, nums);
}
static void Main() {
int n = 3;
int k = 5;
Console.WriteLine(kthPermutation(n, k));
}
}
// Function to solve recursively
function solve(n, k, fact, nums) {
// Base case
if (n === 0) {
return "";
}
// Find which unused digit should come next
let c = Math.floor(k / fact[n - 1]) + 1;
let str = "";
// Traverse all digits
for (let i = 0; i < nums.length; i++) {
// Count only unused digits
c -= (nums[i] === 0 ? 1 : 0);
// If c becomes 0, select this digit
if (c === 0 && nums[i] === 0) {
// Mark digit as used
nums[i] = 1;
// Add digit to answer
str += String(i + 1);
break;
}
}
// Recursively solve for remaining digits
return str + solve(n - 1,
k % fact[n - 1],
fact, nums);
}
function kthPermutation(n, k) {
// Create factorial array
let fact = new Array(n + 1).fill(1);
for (let i = 1; i <= n; i++) {
fact[i] = i * fact[i - 1];
}
// Array to track used digits
let nums = new Array(n).fill(0);
// Convert k into 0-based indexing
k--;
// Find kth permutation
return solve(n, k, fact, nums);
}
// Drive code
let n = 3;
let k = 5;
console.log(kthPermutation(n, k));
Output
312