[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.
思路:在《找出较大的下一个数字组合 Next Permutation》里,可以根据一种组合求得其相邻且较大的下一个组合。依据这样可以依次找到第k个数。但这样的效率太低了。况且两个问题题的条件是不一样的,之前那个问题的条件并不知道已知的组合是第几个数,而当前问题并不要求我们求出全部前k个数。
因此,不依次求到第k个数。可以根据k的值来直接构造。首先对于任一个数n,其组合个数都是知道的。分别是1!=1,2!=2,3!=6,4!=24,5!=120……这些组合数可以认为是某个位上的权值。
那么对于某一个n, k,比如n=4, k=17。首先知道n以下的组合数有6,2,1。那么17 = 2*6 + 2*2 + 1,
由于权值6的倍数是2,且有剩余,所以第4位(最高位)的值是从“1234”中选第3小的数,也就是3;
由于权值2的倍数是2,且有剩余,所以第3位的值是从“124”中选第3小的数,也就是4;
由于权值1的倍数是1,且没有剩余,所以第2位的值是从“12”中选第1小的数,也就是1;
最后剩下数,逆序追加到后面。
这个过程和人脑去寻找第k大数的过程很接近。
class Solution {
public:
//Remove the idx'th num from s
//取出第idx个数字
string removeidx(string s, int idx, char &c)
{
c = s[idx-1];
string s1 = s.substr(0, idx-1);
string s2 = s.substr(idx);
return s1 + s2;
}
string getPermutation(int n, int k) {
if(n > 9 || n<1)
return "";
string full = "123456789";
int A[9] = {1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
if(A[n-1] < k)
return "";
string s = full.substr(0, n); //1st permutation sequence
if(k == 1) //第一个数,直接返回
return s;
if(k == A[n-1]) //最后一个数,逆转后直接返回
{
reverse(s.begin(), s.end());
return s;
}
string result = "";
int count;
char c;
for(int i=n-2;i>=0;i--)
{
count = 0;
if(k < A[i]) //如果该位上没有个数,就选最小的一个数
{
s = removeidx(s, 1, c);
result += c;
continue;
}
while(k >= A[i]) //count求得该位上的个数
{
k -= A[i];
count++;
}
if(k == 0) //全部减完,可以剩下的部分逆置来得到最大
{
s = removeidx(s, count, c);
result += c;
reverse(s.begin(), s.end());
return result + s;
}
else //还没有减完,取得第count+1小的数来作该位
{
s = removeidx(s, count+1, c);
result += c;
}
}
}
};
上面的方法和《找1~n的自然数十进制形式中1的个数》所用的方法类似,http://blog.csdn.net/ojshilu/article/details/17089993