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)
链接:https://leetcode-cn.com/problems/permutation-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题
next_permutation 硬求,时间空间都很慢;
尝试通过n和k直接求出下一个排序;
当第一个数为1时,后面n-1个数有n-1!种排序方法,若k大于n-1!,则第一个数取2;
由此可得,k/(n-1!)的值为第一个数要取的数的下标;
取出后再原本的从1到n的列表中删除取出的数,用string储存的话可以用erase删除;
k=k%(n-1!),为剩下的数要解决的排序数量;
接下来剩下n-1个数,确定第二个数,通过k/(n-2!)找到新加入的数的下标;
终止条件
当只剩2个数时,k%1一定为0,所以余数为0为终止条件,最后把剩余的一个数加入结果即可;;
若前面还剩多个数时,k%n-1!为0,则这次添加完后,后续按原先顺序添加即可;
class Solution {
public:
string getPermutation(int n, int k) {
string s = "";
for(int i=1;i<=n;i++) s+=to_string(i);
string res="";
--k;
while(k>0)
{
int i =k/f(n-1); //存放除数
res+=s[i];
s.erase(s.begin()+i);
k %=f(n-1);
--n; //n=2的时候,还剩下2个数,k%1必等于0了
}
return res+s;
}
private:
int f(int n) //求阶乘
{
int sum=1;
for(int i=2;i<=n;i++) sum*=i;
return sum;
}
};
next_permutation
class Solution {
public:
string getPermutation(int n, int k) {
string s = string("123456789").substr(0,n);
for(int j = 1; j < k; ++j) next_permutation(s.begin(), s.end()); //罪过 罪过, 谢罪!
return s;
}
};