给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。
示例 1:
输入:n = 3, k = 3
输出:“213”
示例 2:
输入:n = 4, k = 9
输出:“2314”
示例 3:
输入:n = 3, k = 1
输出:“123”
提示:
1 <= n <= 9
1 <= k <= n!
第一种无脑回溯,使用深度优先搜索把所有可能的组合枚举出来,然后每个组合放入一个vector容器里,返回指定序列
class Solution {
public:
void dfs(vector<int> &s,int K,vector<bool> &path,int n,int &temp,int tar)
{
if(K==n)
{
s.push_back(temp);
return;
}
for(int i=0;i<n;i++)
{
if(path[i]==false)
{
temp=temp*10+i+1;
path[i]=true;
dfs(s,K+1,path,n,temp,tar);
if(s.size()==tar) break;
temp=temp/10;
path[i]=false;
}
}
}
string getPermutation(int n, int k)
{
vector<int> s;
vector<bool> path(n,false);
int temp=0;
dfs(s,0,path,n,temp,k);
// sort(s.begin(),s.end()); 这里dfs后s里本身就是有序的,不需排序;
string ret;
stringstream ss;
ss<<s[k-1];
ss>>ret;
return ret;
}
第二种是寻找其数学规律,先贴代码
int F(int n,vector<int> &memo)
{
if(memo[n]!=0) return memo[n];
else if(n==0 || n==1) return 1;
int ret=F(n-1,memo)*n;
memo[n]=ret;
return ret;
}
string Ret(vector<int> &ret)
{
string s;
int a=0;
for(int i=0;i<ret.size();i++)
{
a=a*10+ret[i];
}
stringstream ss;
ss<<a;
ss>>s;
return s;
}
string getPermutation(int n, int k)
{
vector<int> path;
for(int i=0;i<=n;i++) path.push_back(i);
vector<int> ret;
vector<int> memo(n+1,0);
memo[0]=1;
memo[1]=1;
int N=n;
while(ret.size()<N)
{
int s=(k%F(n-1,memo)==0)? k/F(n-1,memo):k/F(n-1,memo)+1;
ret.push_back(path[s]);
path.erase(path.begin()+s);
if(ret.size()==N-1)
{
ret.push_back(path[path.size()-1]);
break;
}
k=(k%F(n-1,memo)==0)? F(n-1,memo):k%F(n-1,memo);
n--;
}
string ans=Ret(ret);
return ans;
}
其中函数F功能是求n的阶乘,带memo可以优化时间。string Ret是输出最终答案的字符串转化函数。
以n=4,k=9为例子,第一个数字可以使1,2,3,4的任一一种,每一种后面又有(n-1)!中排序,这里9/(n-1)!=9/3!=9/6=1,且9%6!=0,说明9不在为1位首的序列中,而是在第二个以2为首的序列中,这就是
int s=(k%F(n-1,memo)==0)? k/F(n-1,memo):k/F(n-1,memo)+1;
这句话的意思,要注意k%(n-1)==0的情况。s算出来是2,以2位首的的序列包含6中情况,他们分别对应k=7、k=8…k=12;此时k=9在这些序列里属于第三个排序,(7,8,9,10,11,12,9是第三个)
k=(k%F(n-1,memo)==0)? F(n-1,memo):k%F(n-1,memo);
这句话便是重定义k,因为此时题目变成了返回在剩下的数字(即1、3、4)所组成的排列里第k个序列,所以需要对k重新定义。现已知首个数字为2,剩下1、3、4三个数字,任何一个数字后面还有2!=2个排序,此时k=3,因此可以判断下个数字选取的是3。重复这些步骤,可以得到最终答案。