LeetCode 60. 第k个排列

186 阅读1分钟

目录:算法日记

题目来源:60. 排列序列

题目描述

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

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

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321" 给定 n 和 k,返回第 k 个排列。

题目示例

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

数据范围

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

算法思路

先高位后低位,考虑每一位应该填什么。 以题目示例为例,当 n=4,k=9n = 4, k = 9 时,先考虑第一位,有以下4种情况:

  • 第一位为1,后接2,3,4的全排列,共 3!=63!=6 种可能;
  • 第一位为2,后接1,3,4的全排列,共 3!=63!=6 种可能;
  • 第一位为3,后接1,2,4的全排列,共 3!=63!=6 种可能;
  • 第一位为4,后接1,2,3的全排列,共 3!=63!=6 种可能; 题目求第9个排列,第一位为1仅有6种排列,因此,第9个排列仅可能出现在以2为第一位的排列中,第一位确定为2。

按上述思路,分别确定每一位的数字,具体过程如下图所示,注意排列中的数字不重复。

未命名文件(12).png

AC代码

function getPermutation(n: number, k: number): string {
    const vis: boolean[] = new Array(10).fill(false);
    let res: string = "";
    for(let i = 1; i <= n; i++) {
        let cnt: number = 1;
        for(let j = 1; j <= n - i; j++) cnt *= j;
        for(let j = 1; j <= n; j++) {
            if(vis[j]) continue;
            if(k <= cnt) {
                res += j.toString();
                vis[j] = true;
                break;
            }
            k -= cnt;
        }
    }
    return res;
};