1. 題目
The set [1,2,3,…,n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):
“123”
“132”
“213”
“231”
“312”
“321”
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.
2. 思路
m個數字的排列形式有m!種。
對N個數排序,按數字序排序下,求k-th序列位的排列形式。
從小往大。因此,如果(N-1)可以排下,則前一位先直接排最小的,然後剩下的再去拍到k序來。
當k在i!和i(i-1)!的的範圍內時,用後i個數字來拍。每次先看用i-1個可以排除多少種。然後看k是幾個(i-1)!的大小,下一個數字就是剩下待排的第幾位。
由於排列是用1開始的,而我們的計算是從0開始的,因此先減去一個1.
BTW:用遞迴求解更簡單。
3. 程式碼
耗時:3ms
class Solution {
public:
Solution() {
p[0] = 1;
for (int i = 1; i < 10; i++) {
p[i] = p[i-1] * i;
}
}
// n個數字最多有n!種, i個數字有i!種
// 如果k的範圍在(i-1)!和i!之間, 則表示只需要i個數字進行排列,剩下的n-i個數字選擇("123..n-i"的字首)
// 如果是j個數字進行排列,則在看k是(j-1)!的x倍,則下一位是第x位的字元,依次往下
string getPermutation(int n, int k) {
string ret;
if (k > p[n]) return ret;
int pos = 1;
for (; pos < 10; pos++) {
if (p[pos] >= k) break;
}
// 構建字首部分
int prefix_num = n - pos;
for (int i = 1; i <= prefix_num; i++) {
ret += `0` + i;
}
// 迭代構建後續的部分
char cond[9];
int j = 0;
for (int i = prefix_num+1; i <= n; i++) {
cond[j++] = `0` + i;
}
cond[j] = ` `;
k--;
for (int i = 1; i < pos; i++) {
// prefix_num + i 位
// 除當前原始外剩下的元素個數 pos - i
int f = k / p[pos-i];
ret += cond[f];
// 刪掉f位置的字元
j--;
for (int x = f; x < j ; x++) { cond[x] = cond[x+1];} cond[j] = ` `;
// 剩下的序排位個數
k %= p[pos-i];
}
ret += cond[0];
return ret;
}
private:
int p[10];
};