1. 题目描述

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

给定 n 和 k,返回第 k 个排列。

说明:

  • 给定 n 的范围是 [1, 9]。
  • 给定 k 的范围是[1, n!]。

示例 1:

  1. 输入: n = 3, k = 3
  2. 输出: "213"

示例 2:

  1. 输入: n = 4, k = 9
  2. 输出: "2314"

2. 解题思路

对于这道题目,我们可以找一些规律,然后再求解。

我们知道,n 个数字的排列一共有 n! 个,以 1 开头的排列有 (n-1)! 个,以 2、3…… n 为开头的也是(n-1)! 个。

以n = 4, k = 9为例,1234的排序如下:
60. 第k个排列 - 图1
我们要选的是第九个数字,每一组是六个数字,可以直接9 % 6 = 3 ,然后在第二组寻找第三个数组就可以了,也就是2314。

我们可以将它们看成不同的组。第 k 个排列落在哪个组,直接到那个组去找,大大缩小了寻找的范围。

这上面就是题目的大致思路了,下面就来看下具体解法。

我们可以先将1- 4 放在数组中:[1,2,3,4],索引 0 对应数字 1,有一个错位,所以我把 k 减 1 处理。

(9-1)/ 3! 取整等于索引1,对应数组中的2,就确定了第一个数为2。

现在就剩下三个数字,那就是在三个数字的全排列中按照上述方法继续寻找。

该方法的时间复杂度为O(n)

3. 代码实现

  1. /**
  2. * @param {number} n
  3. * @param {number} k
  4. * @return {string}
  5. */
  6. var getPermutation = function(n, k) {
  7. const nums = []
  8. let factorial = 1 // 阶乘的结果
  9. for(let i = 1; i <= n; i++){
  10. nums.push(i)
  11. factorial = factorial * i
  12. }
  13. k --
  14. let resStr = ''
  15. while(nums.length > 0){
  16. factorial = factorial / nums.length
  17. const index = k / factorial | 0
  18. resStr += nums[index]
  19. nums.splice(index, 1)
  20. k = k % factorial
  21. }
  22. return resStr
  23. };

4. 提交结果

60. 第k个排列 - 图2