题目如下:
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.
题目意思是根据给定的n和k,生成指定位置的全排列。
如果采用穷举,可能会超时,虽然这里n<=9, 9!,数量也是很可观的。因此可以根据给定的k,进行范围缩减,输出结果。
下面给出详细的过程:
需要辅助空间n,给定例子,假设n=4, k=11
辅助空间c[n],存储的是当前情况下,以i(1<=i<=n)开头的最后一个字符串所在的下标,例如,当第一次迭代时,以1开头的最后一个字符串为1432,它的下标是6;以2开头的最后一个字符串是2431,它的下标是12,等等。采用这个辅助空间的作用是根据k确定落在以哪一个开头的空间内,则可以确定第一个数字,依次相同。
k=11,落在以2开头的字符串中,找到第一个字符2,将2对应的值变为0,表示2已经使用过;更改k, k = k - c[2-1]=5;更新辅助空间c[n]
这一轮对应的是第二个字符,1开始的占前两个,3开始的占中间2个,4开始的在最后两个。此时的k=5,找到位置为4,将c[4]置为0,更改k=5-4=1;
更新c[n]
这轮迭代对应的是第三个字符,此时k=1,找到1,而且此时c[1]=k,c[1]=0,终止迭代,此时c[n]里面可能还有很多不为0的值,反序打印即可得到结果。
代码如下:
public class Solution {
public String getPermutation(int n, int k) {
int[] c = new int[n];
StringBuilder sb = new StringBuilder();
int jieceng = getJieceng(n-1);
// k = Math.abs(jieceng - k - 1);
for(int i = 0; i < n; i++){
c[i] = jieceng * (i + 1);
}
boolean flag= false;
int level = n - 1;
while(true){
if(flag){
for(int i = n-1; i >= 0; i--){//反序打印数组中剩余的值
if(c[i] != 0){
sb.append(i + 1);
}
}
break;
}
int i = 0;
for(; i<n; i++){
if(k > c[i]){//根据k找到相应的位置
continue;
}else if(k == c[i]){//当k==c[i]时,所有的迭代终止
sb.append(i+1);
c[i]=0;
flag = true;
break;
}else if(i == 0){//当i==0时,不能用k-c[i-1]得到k,此时k其实不用变化
level--;
c[i] = 0;
sb.append(i+1);
break;
}else{
for(int j = i - 1; j >=0; j--){
if(c[j] != 0){//更新k
k = k - c[j];
break;
}
}
level--;
c[i] = 0;
sb.append(i+1);
break;
}
}
jieceng = getJieceng(level);
int times = 1;
for(int j = 0; j < n; j++){//更新数组c[n]
if(c[j] != 0){
c[j] = jieceng * times;
times++;
}
}
}
return sb.toString();
}
private int getJieceng(int n){//求阶层
int sum = 1;
for(int i = 1; i<= n; i++){
sum *= i;
}
return sum;
}
}