链接:
https://leetcode.com/problems/permutation-sequence/
大意:
给定整数n和k,要求在[1,n]所有长度为n的全排列中找出第k大的全排列。其中,1<=n<=9,1<=k<=n!。例子:
思路:
穷举法是个思路,但是不可取,因为时间复杂度太大。可以尝试使用数学归纳的方法解决。对于例子n=4,k=9进行分析:
首先,第一个位置(最左边)的取值有四种情况,当第一个位置确定后,后面的三个位置的组合有3!=6种情况。我们可以分下组:
第0组:0xxx-0yyy 组内共有6个元素(记为该组的0到5号)
第1组:1xxx-1yyy 组内共有6个元素(记为该组的0到5号)
第2组:2xxx-2yyy 组内共有6个元素(记为该组的0到5号)
第3组:3xxx-3yyy 组内共有6个元素(记为该组的0到5号)
则对于k=9,也就是选取第9个元素,它在第1组的第2号元素(每组6个元素,组号和元素序号都是从0开始,元素个数k从1开始)。
而第一组我们可以知道它的首位置肯定是1,确定为1后,k应该变为3(表示是该组中的第3个元素,不是第3号)。因此可以确定第一位是1.那么第一位确定是1之后,且此时应该把1置为已访问。此时第二位数字可能是2,3或4。同样,对于第二个数字我们也可以分组:
第0组:12xx-12yy 组内共有2个元素(记为该组的0到1号)
第1组:13xx-13yy 组内共有2个元素(记为该组的0到1号)
第2组:14xx-14yy 组内共有2个元素(记为该组的0到1号)
则对于此时的k=3,我们可以发现它应该是第1组的第0号元素。也就是第2位数字应该为3,既然是第0号元素,也就是说第一位为1,第二位为3,那么后面的元素就应该是未访问元素的升序排列。所以可得最终为 "1324"
主要就是分组,确定在哪个组即确定了在对应位置上的数字。
代码:
class Solution {
public String getPermutation(int n, int k) {
boolean[] visited = new boolean[n + 1]; // 记录各个数字是否被访问
int jie = 1,j = 1; // jie记录继承 初始化为 (n - 1)!
while (j < n) {
jie *= j++;
}
StringBuilder sb = new StringBuilder();
while (sb.length() < visited.length - 1) {
int s = (k - 1) / jie, mod = (k - 1) % jie, i = 1, count = -1; // s为组序号 mod为在组内元素的序号(组和序号都是从0开始)
while (count < s) {
if (!visited[i]) {
count++;
if (count == s)
break;
}
i++;
}
sb.append(i);
visited[i] = true;
// mod为0则表示剩下的数是未被访问的数的升序排列
if (mod == 0) {
for (int x = 1; x < visited.length; x++) {
if (!visited[x])
sb.append(x);
}
break;
}
jie /= --n;
k = mod + 1; // k = mod+1 因为k表示是第几个,从1开始
}
return sb.toString();
}
}
结果:
结论:
数学找规律,找到了就能以最小的时空复杂度解决。