leetcode:60. 排列序列

题目

给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

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

给定 nk,返回第 k 个排列。

示例:

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

提示:

  • 1 <= n <= 9
  • 1 <= k <= n!

解答 & 代码

对于 n 个元素的排列,假设第 k 个排列(即本题所求的结果)为 [困难] 60. 排列序列 - 图1
首先要确定第一个元素[困难] 60. 排列序列 - 图2的值,[困难] 60. 排列序列 - 图3有 1, 2, …, n 这 n 种取值,对于每个取值作为[困难] 60. 排列序列 - 图4,都有 (n-1)! 种排列,因此 [困难] 60. 排列序列 - 图5
同理,确定了[困难] 60. 排列序列 - 图6后,再依次确定[困难] 60. 排列序列 - 图7, [困难] 60. 排列序列 - 图8……
假设当前要确定元素[困难] 60. 排列序列 - 图9

  • 说明前面的 i 个元素[困难] 60. 排列序列 - 图10已经确定,还剩 n - i 个数未被使用,可以作为[困难] 60. 排列序列 - 图11的取值,而每个取值都有 (n - i - 1) 种排列,因此[困难] 60. 排列序列 - 图12是第[困难] 60. 排列序列 - 图13个未使用的数(数值要 + 1)
  • 确定了[困难] 60. 排列序列 - 图14后,k 取余数

在实际的代码中,可以首先将 k 的值减少 1,这样可以减少运算,降低代码出错的概率:

  1. [困难] 60. 排列序列 - 图15是剩余未使用的数中的第[困难] 60. 排列序列 - 图16个数(数值要 +1)
  2. [困难] 60. 排列序列 - 图17

    1. class Solution {
    2. public:
    3. string getPermutation(int n, int k) {
    4. int factorial = 1; // 阶乘
    5. for(int i = 1; i < n; ++i)
    6. factorial *= i; // 初始化为 (n-1)!
    7. vector<bool> used(n, false); // 标记每个数字是否已被使用
    8. string result(n, ' '); // 结果
    9. k -= 1; // k 先减 1(相当于从 0 开始编号,避免出错)
    10. // 确定每一位
    11. for(int i = 0; i < n; ++i)
    12. {
    13. // ai 是剩余未使用的数中的第 order=k/(n-i-1)! 个数
    14. int order = k / factorial;
    15. for(int j = 0; j < n; ++j) // 找第 order=k/(n-i-1)! 个未使用的数
    16. {
    17. if(used[j] == false && order == 0)
    18. {
    19. result[i] = '0' + j + 1; // 数值要 +1(因为从 0 开始记)
    20. used[j] = true; // 标记为已使用
    21. break;
    22. }
    23. else if(used[j] == false)
    24. --order;
    25. }
    26. if(i != n - 1) // 注意这个条件,避免 factorial 的除数为 0
    27. {
    28. k = k % factorial; // 更新 k 的取值
    29. factorial = factorial / (n - i - 1); // 更新阶乘
    30. }
    31. }
    32. return result;
    33. }
    34. };

    复杂度分析:

  • 时间复杂度[困难] 60. 排列序列 - 图18
  • 空间复杂度 O(n):

执行结果:

  1. 执行结果:通过
  2. 执行用时:0 ms, 在所有 C++ 提交中击败了 100.00% 的用户
  3. 内存消耗:5.8 MB, 在所有 C++ 提交中击败了 67.72% 的用户