给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k,返回第 k 个排列。
示例 1:
输入:n = 3, k = 3
输出:"213"
示例 2:
输入:n = 4, k = 9
输出:"2314"
示例 3:
输入:n = 3, k = 1
输出:"123"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-sequence
解题思路
为了去掉不必要的计算, 想要直接找到第k个全排列序列
首先明确: 序列长度为n时
比如药确定第一位数字, 先假定为1, 那剩下有几种可能? count = (n-1)!
种
如果 k > count, 则说明第一位不是 1, 反过来如果 k <= count, 则说明第一位是 1
以此类推, 找出每一位
代码
class Solution {
int[] factorial;
public String getPermutation(int n, int k) {
StringBuilder path = new StringBuilder();
calculateFactorial(n);
boolean[] used = new boolean[n];
dfs(n, k, used, path);
return path.toString();
}
private void dfs(int n, int k, boolean[] used, StringBuilder path) {
if (path.length() == n) {
return;
}
// count是当前想要确定的这一位数取定时后续序列的个数
// 也就是 count = (n - 1)!
int count = factorial[n - 1 - path.length()];
for (int i = 0; i < n; i++) {
// 如果当前数已经取出, 跳过
if (used[i]) {
continue;
}
// count < k 则当前元素不是该位置应该取出的数
if (count < k) {
// 将k减掉count
k -= count;
continue;
}
// 选定了加追加到结果
path.append(i + 1);
// 并标记为已取出
used[i] = true;
dfs(n, k, used, path);
return;
}
}
/**
* 计算出n的阶乘存到数组
* 数组第0个元素对应 0!, 第1个元素对应 1!, 以此类推
*
* @param n 计算阶乘
* @return void
*/
private void calculateFactorial(int n) {
factorial = new int[n + 1];
factorial[0] = 1; // 0! = 1
for (int i = 1; i <= n; i++) {
factorial[i] = i * factorial[i - 1];
}
}
}