给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123” “132” “213” “231” “312” “321” 给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。 给定 k 的范围是[1, n!]。 示例 1:
输入: n = 3, k = 3 输出: “213” 示例 2:
输入: n = 4, k = 9 输出: “2314”
//算阶乘
public static int factorial(int n) {
int sum = 1;
for (int i = 2; i <= n; i++) {
sum *= i;
}
return sum;
}
public static String getPermutation(int n, int k) {
if (n == 1) {
return "1";
}
boolean[] visit = new boolean[n];
return visit(n, k, visit);
}
//递归,以n=4,k=8为例
//首先会根据偏移1找到数字2,可是看做1234变为2134,当然实际是用visit标记
//然后考虑2134的第二位关于2的阶乘的偏移,会发现不需要变,所以还是2134
//然后找到关于第三位的偏移量是1,所以2134会变成2143
//最后一位不变,得到结果2143
public static String visit(int n, int k, boolean[] visit) {
//先算出3!== 6
int sum = factorial(n - 1);
//得到要交换的位置是1,起始偏移为0
//即1234要将数字2交换到前面
int swapPos = (k - 1) / sum;
//算出交换后还有多少个组合要算,这个例子里面是2
int remain = k - swapPos * sum;
int i = 0;
//由于有些位上的数字可能已经visit,所以要排除一下
for (; i < visit.length && swapPos >= 0; i++) {
if (!visit[i]) {
swapPos--;
}
}
//得到i=2,所以visit[1] = true
visit[i - 1] = true;
//继续递归,返回的是当前的数字2以及下次递归返回的部分
if (n > 1) {
return String.valueOf(i) + visit(n - 1, remain, visit);
} else {
//当递归到最后一位时,就可以直接返回当前数字
return String.valueOf(i);
}
}
这道题目要达到1ms,字符串拼接转换要用String.ValueOf或者Integer.ToString才行