LeetCode 60. 第k个排列
题目
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。
示例 1:
输入: n = 3, k = 3
输出: “213”
示例 2:
输入: n = 4, k = 9
输出: “2314”
分析
由于以前做过 leetcode 31 下一个排序,所以首先想到直接调用此函数k次,就可以生成第k个排序。但是似乎有点满。考虑数学方法,假如有n个数,那么第一个数是(0,n)之间任意数的概率都是n!/n,即(n-1)!,
用(k-1)/(n-1)!得到的结果即是当前需要的插入的数字在备选区的位置。
处理后将当前数移除备选区,依次以相同方法处理第二位至最后一位即可。
依次生成
class Solution {
public:
string getPermutation(int n, int k) {
string res = "";
for(int i = 1; i <= n; i++){
res += '0' + i;
}
for(int i = 0; i < k - 1; i++){
res = nextPermutation(res);
}
return res;
}
string nextPermutation(string s){
int len = s.size();
int k = -1, l = 0;
for(int i = len - 2; i >= 0; i--){
if(s[i] < s[i + 1]){
k = i;
break;
}
}
if(k == -1){
reverse(s.begin(), s.end());
return s;
}
for(int i = len - 1; i >= 0; i--){
if(s[i] > s[k]){
l = i;
break;
}
}
swap(s[k], s[l]);
reverse(s.begin() + k + 1, s.end());
return s;
}
};
数学方法
class Solution {
public:
string getPermutation(int n, int k) {
string res;
vector<char> temp(n);
for(int i = 0; i < n; i++){
temp[i] = '1' + i;
}
for(int i = 0; i < n; i++){
int f = helper(n - i - 1);
int t = (k -1 ) / f;
k -= f * t;
res += temp[t];
temp.erase(temp.begin() + t);
}
return res;
}
int helper(int x){
if(x <= 1){
return 1;
}else{
return x * helper(x - 1);
}
}
};