T60. Permutation Sequence【Medium】
题目
集合 [1,2,3,...,n] 包含了 n! 个不同的排列。
当 n = 3 时,有下列的排列组合:
- "123"
- "132"
- "213"
- "231"
- "312"
- "321"
给定 n 和 k, 返回第 k 个序列。
注意:n 在 1~9 之间
思路
大家都知道,n个数字有 n! 种排列组合。
但是由于是按顺序的,下面代码的关键在于给结果分块。
例如上面的例子:
"123"
"132"
"213" "123" "132" 是一部分
"231" 按首字母相同,分成三块 --> "213" "231" 是一部分
"312" "312" "321" 是一部分
"321"
然后这样继续往下分。
所以当 n 个数字就可以分成 n 组有 (n-1)! 种排列组合的部分,然后往下分。
把给出的 (k-1)/(n-1)! 就得到要找的是在第几个部分,同时也确定了首字母。
例如,上面的例子,k = 4 时, 代表在第二部分,首字母为 2。
选到第二部分以后,把 k 重新设置成 2,也就是对应的第二部分的 k 值,对第二部分重复刚才的操作,然后就得到了正确的答案。
可能这样说起来还是有点复杂,可以 debug 一下代码看看各个参数的变化体会一下可能会清晰一些(我就是这样看才发现了这代码想干嘛的/(ㄒoㄒ)/)
代码
代码取自 Top Solution,稍作注释
public String getPermutation(int n,int k){
int pos = 0;
List<Integer> numbers = new ArrayList<>();
int[] factorial = new int[n+1];
StringBuilder sb = new StringBuilder();
int sum = 1;
factorial[0] = 1;
// 创建一个 {1, 1, 2, 6, 24, ... n!}这样的数组
for(int i=1; i<=n; i++){
sum *= i;
factorial[i] = sum;
}
// 按顺序创建一个{1,2,...n}的数组
for(int i=1; i<=n; i++){
numbers.add(i);
}
k--;
//这里是主要思路,来实现思路里说的情景
for(int i = 1; i <= n; i++){
int index = k/factorial[n-i];
//找到这个 index 对应的下一个数字,添加到 StringBuilder 里面
sb.append(String.valueOf(numbers.get(index)));
numbers.remove(index);
//把 k 减去 index*factorial[n-i],设置为下个循环部分里面对应的 k 的值
k-=index*factorial[n-i];
}
return String.valueOf(sb);
}