Leetcode60. 第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"
题解:
复杂度分析:
- 时间复杂度: O ( N 2 ) \mathcal{O}(N^2) O(N2),从列表中删除元素,共执行操作次数: N + ( N − 1 ) + . . . + 1 = N ( N − 1 ) / 2 N + (N - 1) + ... + 1 =N(N - 1)/2 N+(N−1)+...+1=N(N−1)/2
- 空间复杂度: O ( N ) \mathcal{O}(N) O(N)。
首先构造 k = 2 k = 2 k=2 的阶乘数:
k = 2 = 1 × 2 ! + 0 × 1 ! + 0 × 0 ! = ( 1 , 0 , 0 ) k = 2 = 1 \times 2! + 0 \times 1! + 0 \times 0! = (1, 0, 0) k=2=1×2!+0×1!+0×0!=(1,0,0)
阶乘中的系数表示输入数组中,除去已使用元素的索引。这符合每个元素只能在排列中出现一次的要求。
第一个数字是 1,即排列中的第一个元素是
n
u
m
s
[
1
]
=
2
nums[1] = 2
nums[1]=2。由于每个元素只能使用一次,则从 nums 中删除该元素。
阶乘中下一个系数为 0,即排列中
n
u
m
s
[
0
]
=
1
nums[0] = 1
nums[0]=1,然后从 nums 中删除该元素。
阶乘中下一个系数也是 0,即排列中
n
u
m
s
[
0
]
=
3
nums[0] = 3
nums[0]=3,然后从 nums 中删除该元素。
算法:
- 生成输入数组,存储从 1 1 1 到 N N N 的数字。
- 计算从 0 0 0 到 ( N − 1 ) ! (N - 1)! (N−1)!的所有阶乘数。
- 在 ( 0 , N ! − 1 ) (0,N!−1) (0,N!−1) 区间内, k k k 重复减 1 1 1。
- 计算 k的阶乘,使用阶乘系数构造排列。
- 返回排列字符串。
java代码:
/**
* @param n
* @param k
* @return
*/
public static String getPermutation(int n, int k) {
int[] fact = new int[n];
ArrayList<Integer> nums = new ArrayList<>();
nums.add(1);
fact[0] = 1;
for (int i = 1; i < n; i++) {
//fact存入0!,1!,2!...,(n-1)!
fact[i] = fact[i - 1] * i;
//nums 存入1,2,3,...,n
nums.add(i + 1);
}
k = k - 1;
StringBuffer str = new StringBuffer();
for (int j = n - 1; j >= 0; j--) {
int x = k / fact[j];
k = k % fact[j];
str.append(nums.get(x));
nums.remove(x);
}
return str.toString();
}