Given a string s of length n (assume characters are distinct) and an integer k (1-indexed), return the k-th permutation of s in lexicographic order.
If the input contains duplicate characters, the factoradic method treats equal characters as distinct positions — to get the k-th unique permutation with duplicates use a frequency-aware method (see related notes).
Generate all permutations of the input string (we already discussed generation methods in All permutations of a string 1 - String has no duplicates and All permutations of a string 2 - String has duplicates). Sort the generated list and return the k-th element. A variant of brute force generates permutations in lexicographic order directly (prefix/suffix recursion), but that still requires enumerating up to k permutations and is therefore inefficient in the worst case.
Write k-1 in the factorial number system (factoradic). Each digit tells which element to pick from the remaining sorted list of characters for the next position.
import java.util.*;
classSolution {
public String kthPermutation(String s, long k) {
int n = s.length();
long[] fact =newlong[n+1];
fact[0]= 1;
for (int i = 1; i <= n; ++i) fact[i]= fact[i-1]* i;
k = k - 1; // 0-index List<Character> nums =new ArrayList<>();
for (char c : s.toCharArray()) nums.add(c);
Collections.sort(nums);
StringBuilder ans =new StringBuilder();
for (int i = n; i >= 1; --i) {
long f = fact[i-1];
int idx = (int)(k / f);
k = k % f;
ans.append(nums.remove(idx));
}
return ans.toString();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classSolution {
funkthPermutation(s: String, kIn: Long): String {
val n = s.length
val fact = LongArray(n+1)
fact[0] = 1for (i in1..n) fact[i] = fact[i-1] * i
var k = kIn - 1Lval nums = s.toCharArray().sorted().toMutableList()
val sb = StringBuilder()
for (i in n downTo 1) {
val f = fact[i-1]
val idx = (k / f).toInt()
k %= f
sb.append(nums.removeAt(idx))
}
return sb.toString()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
classSolution:
defkth_permutation(self, s: str, k: int) -> str:
n = len(s)
fact = [1] * (n +1)
for i in range(1, n +1):
fact[i] = fact[i-1] * i
k -=1# convert to 0-index nums = sorted(list(s))
ans: list[str] = []
for i in range(n, 0, -1):
f = fact[i-1]
idx = k // f
k %= f
ans.append(nums.pop(idx))
return''.join(ans)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pubstructSolution;
impl Solution {
pubfnkth_permutation(s: String, mut k: usize) -> String {
letmut nums: Vec<char>= s.chars().collect();
nums.sort();
let n = nums.len();
letmut fact =vec![1usize; n+1];
for i in1..=n { fact[i] = fact[i-1] * i; }
k -=1; // 0-index
letmut ans = String::with_capacity(n);
for i in (1..=n).rev() {
let f = fact[i-1];
let idx = k / f;
k %= f;
ans.push(nums.remove(idx));
}
ans
}
}
Starting from the smallest permutation (sorted input), calling next_permutation repeatedly advances lexicographic order by one. Doing this k-1 times yields the k-th permutation.