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.
这道题是找到第 i 个排列系列。
这道题更像是一道数学找规律题。我考虑了一段时间才找到规律。但又碰到了超时问题,又花了一些时间才解决。
当n = 3时候,数组为[1, 2, 3]
我们先来找规律:为了方便,假设序号从0开始排。
我们以5. "3 2 1"为例。
先考虑第0位,为什么是3呢?
我们推算得到 5 / 2 = 2。同样的,对于序列为4的,也有4 / 2 + 1 = 2,对于序列为3的,也有3 / 2 + 1 = 1。
在当前的[1, 2, 3]数组中,第 2 位正是3,第1位正是2。
所以我们似乎找到了第0位的规律。
接下来考虑第1位。
我们要将当前的5进行更新 5 - 2 * 2 = 1 (相当于去除第0位的影响)
1 / 1 = 1,
在当前的[1, 2, 3]数组中,第1位正是2.
接下来第2位。
将1 进行更新 1 - 1 * 1 = 0
在当前的[1,2,3]数组中,取第0位正是1。
所以,序列5为"321"
总结:
创建store数组,存储要生成的序列信息
创建isUsed数组,标记原数组中元素的使用情况。
1. 计算index = k / ( n - 1 ) * ( n - 2) *...*1;
2. 找到数组中没有被使用的第index的值,这个值即为store当前最高位的值。(从0开始)
3. 更新 k = k - index * (n - 1) * (n - 2) *...*1; isUsed[index] = true
4. 继续重复1,2,3,填充store当前最高位。
注意:
我们会大量计算 n * ( n - 1 ) ... 1这类阶乘。
将它存储到数组 array [ n ] 中去,比如index = 0的存储,1 ! ,index= 1的存储 2!
这样节约时间,不然会超时!
最后运行时间:
代码:
public class PermutationSequence {
public String getPermutation(int n, int k) {
boolean[] isUsed = new boolean[n];
int[] store = new int[n];
int[] cumuMulti = new int[n];
cumuMulti[0] = 1;
//store i! cumuMulti[i] = (i + 1 ) !
for (int i = 1; i < n; i++) {
cumuMulti[i] = (i + 1) * cumuMulti[i - 1];
}
k--;
int curN = n;
while (curN > 0) {
int count = 0;//mean the count th unused value
int div = 0;
if (curN - 1 != 0) {
div = cumuMulti[curN - 1 - 1];
count = k / div;
}
int i = 0;
int curCount = -1;
for (; i < n; i++) {
if (!isUsed[i]) {
curCount++;
}
if (count == curCount) {
break;
}
}
store[n - curN] = i + 1;
isUsed[i] = true;
k = k - div * count;//update, to the next position
curN--;// to the next position
}
StringBuilder sb = new StringBuilder();
for (int v : store) {
sb.append(v);
}
return sb.toString();
}
}