leetcode习题集——60. 第k个排列
题目
给出集合 [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”
算法1
public class P60_PermutationSequence {
public String getPermutation(int n, int k) {
int[] nums = new int[n];
for(int i = 0;i<n;i++){
nums[i] = i+1;
}
for(int i=1;i<k;i++){
nextPermutation(nums);
}
StringBuilder s = new StringBuilder();
for(int i = 0;i<n;i++){
s.append(nums[i]);
}
return s.toString();
}
private void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i + 1] <= nums[i]) {
i--;
}
if (i >= 0) {
int j = nums.length - 1;
while (j >= 0 && nums[j] <= nums[i]) {
j--;
}
swap(nums, i, j);
}
reverse(nums, i + 1);
}
private void reverse(int[] nums, int start) {
int i = start, j = nums.length - 1;
while (i < j) {
swap(nums, i, j);
i++;
j--;
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
思路:
参考leetcode习题集——31. 下一个排列
- 从第一个排列按顺序求到第k个排列
算法2
public class P60_PermutationSequence2 {
public String getPermutation(int n, int k) {
char[] arr = new char[n];
//第1个排列
for (int i = 1; i <= n; i++) {
arr[i - 1] = (char) (i + '0');
}
int cur = 0;
int remain = k - 1;
while (remain > 0) {
int step = getFactorial(n - cur - 1);
int loop = remain / step;
for (int i = 1; i <= loop; i++) {
char tmp = arr[cur];
arr[cur] = arr[cur + i];
arr[cur + i] = tmp;
}
remain = remain % step;
cur++;
}
return new String(arr);
}
private int getFactorial(int n) {
int ret = 1;
for (int i = 2; i <= n; i++) {
ret *= i;
}
return ret;
}
}
思路:
- 从左开始遍历,当前遍历的下标为
cur
,当前剩余排列数remain=k-1
-
cur
开始的n-cur-1
会产生(n-cur-1)!
个排列,取名为step
-
loop
为remain
与step
的商,代表消耗的顺序排列次数
-
loop
为1,即下(n-cur-1)!
个排列即为交换后的结果 -
loop
为1,即下(n-cur-1)!
个排列即为交换后的结果,后续的依此类推
- 重复以上过程直到
remain
为0