Problem:
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.
这一题是要求给出[1,2,3,...,n],然后对其进行升序的全排列,然后给定一个k,求出第k项是哪个数。刚刚写完31题的求下一个序列,所以就马上有一个想法是给出初始序列1234...n然后再给出k,然后用next_permutation(vector<int>, int)来实现。但是我简单算了一下复杂度,最坏情况是n!次,最好是O(1),平均的话应该也差不多是O(n!),这个肯定是超时的。所以上网搜了一下关于全排列的算法,发现了完全合胃口的康拓展开:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!
用例子来说明,假如一个序列 4321,比4小的有1,2,3这三个数,确定首位后,后面有3!种情况,所以有3*3!=18种。
然后看3,比3小有2个数,确定这位后,后面有2!种情况,所以有2*2!种,也就是4种。然后看2,比2小有1个,后面有1!种,也就是1种。看最后一位1,没有比它小的了,0种,所以比4321小的一共有18+4+1=23个。所以4321是第24小的数。
然后这道题可以用康拓的逆展开,也就是求第K项的。
以下例子摘自百度百科:
{1,2,3,4,5}的全排列,并且已经从小到大排序完毕
找出第96个数
首先用96-1得到95
用95去除4! 得到3余23
有3个数比它小的数是4
所以第一位是4
用23去除3! 得到3余5
有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
用5去除2!得到2余1
有2个数比它小的数是3,第三位是3
用1去除1!得到1余0
有1个数比它小的数是2,第二位是2
最后一个数只能是1
所以这个数是45321
Code:(LeetCode运行9ms)
class Solution {
public:
string getPermutation(int n, int k) {
string s = "";
for (int i = 1; i <= n; i++) {
s += ('0' + i);
}
return find_kth_permutation(s, k);
}
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
string find_kth_permutation(string s, int k) {
int length = s.size();
string result = "";
int factor = factorial(length - 1);
k--;
for (int i = length - 1; i > 0; k %= factor, factor /= i, i--) {
//找有m个比k/factor小的数,就是要求序列的这一位。
auto tmp = next(s.begin(), k / factor);
result += *tmp;
s.erase(tmp);
}
result += s[0];
return result;
}
};