给出集合 [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”
提示:
1 <= n <= 9
1 <= k <= n!
为了高效解决这个问题,我们使用数学方法直接计算第 k
个排列,避免枚举所有排列。核心思路是逐位确定排列中的每个数字:
0!
到 (n-1)!
的值,用于后续计算每个位置的数字。1
到 n
的列表。k
减 1(因为排列索引从 0 开始)。i
位(i
从 0
开始),剩余数字个数为 m = n - i
。index = k / (m-1)!
。k
:k = k % (m-1)!
。数学原理:
n
个数字的排列,第一位有 n
种选择,每种选择对应 (n-1)!
种排列。k / (n-1)!
可以确定第一位的数字索引。k
为余数后,递归处理剩余数字,直至确定所有位。class Solution {
public String getPermutation(int n, int k) {
// 计算0!到(n-1)!的阶乘数组
int[] factorial = new int[n];
factorial[0] = 1; // 0! = 1
for (int i = 1; i < n; i++) {
factorial[i] = factorial[i - 1] * i;
}
// 初始化可用数字列表(1~n)
List<Integer> nums = new ArrayList<>();
for (int i = 1; i <= n; i++) {
nums.add(i);
}
// 调整k为从0开始的索引
k--;
StringBuilder result = new StringBuilder();
// 逐位确定数字
for (int i = n - 1; i >= 0; i--) {
// 计算当前位的索引
int index = k / factorial[i];
// 取出该索引对应的数字并移除
result.append(nums.remove(index));
// 更新k为余数
k %= factorial[i];
}
return result.toString();
}
}
阶乘数组初始化:
factorial[i]
存储 i!
的值(i
从 0
到 n-1
)。n=4
时,factorial = [1, 1, 2, 6]
(对应 0!, 1!, 2!, 3!
)。可用数字列表:
[1, 2, ..., n]
,每次确定一位后移除已使用的数字。索引调整:
k
减 1 转换为从 0 开始的索引(例如第 1 个排列视为索引 0)。循环确定每位数字:
index = k / factorial[i]
确定当前位在剩余数字中的位置。k = k % factorial[i]
用于计算下一位。时间复杂度:O(n²),其中:
ArrayList
的 remove
方法平均 O(n))。空间复杂度:O(n),用于存储阶乘数组和数字列表。
阅读
,我的力扣算法题解专栏
正在持续更新,欢迎大家订阅!!如果觉得这篇内容对你有帮助,别忘了点赞+收藏+关注
哦!!你的支持,将是我创作的最大动力