题目:
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]共有n!种不同的排列。
把这些排列按照字符串顺序排列,找出第k个排列。比如对于n=3时有以上六种排列,第五个排列就是312.
思路:解决该题目最蛮力的方法是找出所有的排列,然后排序后找出第k个,时间复杂度将会达到O(n!+nlgn),太低效!
观察全排列的规律我们可以发现,如果是有n个数字,那么第一位上可以有n个不同的选择,第二位到第n位一共有(n-1)!种情况,也就是说第一位的每一个数字确定后,后面的n-1位会有(n-1)!种不同的可能。比如上面的例子中,当第一位是1时,后两位有两种可能,当然第一位是2或者3时也是如此。
那么我们就可以用来确定第m位的数值。我们从第一位往后依次确定各位的数值,所以确定第m位时代表前m-1位已经确定。由于第m+1到第n一共有n-m个位置,共有可能性(n-m)!,所以说第m位每个数值对应有(n-m)!个可能值。那么第m位上的数值应该是第 index = k/(n-m)! + ((k%(n-m)! != 0)?1:0)位数;使用一个char数组代表哪些数字已经使用过了,使用过了则改为’ ‘,否则应该是’0’,’1’..’9’之类,所以只需要依次遍历该数组就可以找到第index位数值。很明显是一个递归过程,依次确定每一位上应该是哪个数字。
以上。
代码如下:
class Solution {
public:
string getPermutation(int n, int k) {
if(n == 1 && k == 1)return "1";
else if(n < 1 || k < 1)return "";
int factorial = 1;
vector<char> ints;
for(int i = 1; i <= n; i++){
ints.push_back(i + '0');
factorial *= i;
}
if(k > factorial)return "";
string result;
return getKthString(factorial/n,ints,k,result,n);//factorial/n即(n-1)!
}
string getKthString(int subFactorial, vector<char>& ints,int k, string& result,int kinds_this_index){
if(kinds_this_index == 1){
for(int i = 0; i < ints.size(); ++i)
if(ints[i] != ' '){
result.push_back(ints[i]);
break;
}
return result;
}
if(k == 1){//如果是确定第m位时需要找的是第一个位置,那么只需要遍历ints数组,依次存入到结果中即可。
for(int i = 0; i < ints.size(); ++i)
if(ints[i] != ' '){
result.push_back(ints[i]);
}
return result;
}
int index = k/subFactorial + ((k%subFactorial != 0)?1:0);//找出第m位上需要存放的是按照顺序的第几个数值。
int count = 0;
for(int i = 0; i < ints.size(); i++){
if(ints[i] != ' ')count++;
if(count == index){
result.push_back(ints[i]);
ints[i] = ' ';
break;
}
}
--kinds_this_index;
return getKthString(subFactorial/kinds_this_index,ints,k - (index - 1)*subFactorial,result,kinds_this_index);
}
};