给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k,返回第 k 个排列。
首先,我们先理解清楚全排列的过程。给定n=3,则123的全排列有{123,132,213,231,321,312};
具体先固定住1,对23进行全排序,然后交换1和2的位置,对13进行全排序,再交换1和3的位置,对21进行全排序。
但这道题目不可采取先递归求全排序所有可能,再取要的答案。因为第5个排列为 312而不是321。所以应考虑从其他角度入手。
当n=1时,有1种排列,
当n=2时,有2种排列,
当n=3时,有6种排列,
其实n=3时,可以拆分成第一位数和 后两位数,后两位数的排列组合为n=2时的两种,那第一位数可以是三个数种的任意一个,所以总的排列数就是23=6
所以我们可以知道,当k<=2时,第一位数没有变,那我们就可以确定第一个数是最小数,那就对剩下的后两位数分析,如果k=1那就确定第二位数是最小数,否则则是第二小数
当2<k<=4时,可以确定第一位数是第二小数,再对后两数分析,如果k=3那第位数就是剩下数里的最小数
所以以此举例n=4,k=9时,我们对k进行判断k如果是在123到1234之间的话,那说明k至少改变了4位,如果k在123到1232之间,说明第一位肯定是2,未确定是数位[1,3,4]
那k=k-6=3,那么k是在12 到123之间,说明k改变了3位,且k在12到12*2之间,那第二位就是3, 剩余未排列[1,4]
k = k-3 = 1,那么说明最后两位k未改变, 那么第三第四位就是1 4
代码如下:
class Solution {
public:
string getPermutation(int n, int k) {
string ans="";
string base="";
for(int i=1;i<=n;i++)
base+=char('0'+i);
if(k==1) return base;
while(k>1)
{
adjust(base,n,k,ans);
}
ans+=base;
return ans;
}
void adjust(string &s, int &n, int &k,string &ans)
{
int cur=jiecheng(n-1);
int i=0;
if(k<=cur )
{
n--;
ans+=s[i];
s.erase(i,1);
cur=jiecheng(n-1);
}
while(k>cur)
{
i++;
k-=cur;
}
ans+=s[i];
s.erase(i,1);
n--;
}
int jiecheng( int n)
{
int val=1;
for(int i=1;i<=n;i++)
val*=i;
return val;
}
};