每天一题LeetCode【第42天】

T60. Permutation Sequence【Medium

题目

集合 [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 之间

思路

大家都知道,n个数字有 n! 种排列组合。

但是由于是按顺序的,下面代码的关键在于给结果分块。

例如上面的例子:

 "123"
 "132"
 "213"                         "123"  "132" 是一部分
 "231"  按首字母相同,分成三块 --> "213"  "231" 是一部分
 "312"                         "312"  "321" 是一部分
 "321"

然后这样继续往下分。

所以当 n 个数字就可以分成 n 组有 (n-1)! 种排列组合的部分,然后往下分。

把给出的 (k-1)/(n-1)! 就得到要找的是在第几个部分,同时也确定了首字母。

例如,上面的例子,k = 4 时, 代表在第二部分,首字母为 2。

选到第二部分以后,把 k 重新设置成 2,也就是对应的第二部分的 k 值,对第二部分重复刚才的操作,然后就得到了正确的答案。

可能这样说起来还是有点复杂,可以 debug 一下代码看看各个参数的变化体会一下可能会清晰一些(我就是这样看才发现了这代码想干嘛的/(ㄒoㄒ)/)

代码

代码取自 Top Solution,稍作注释

public String getPermutation(int n,int k){
        int pos = 0;
        List numbers = new ArrayList<>();
        int[] factorial = new int[n+1];
        StringBuilder sb = new StringBuilder();
        int sum = 1;
        factorial[0] = 1;
        // 创建一个 {1, 1, 2, 6, 24, ... n!}这样的数组
        for(int i=1; i<=n; i++){
            sum *= i;
            factorial[i] = sum;
        }
        // 按顺序创建一个{1,2,...n}的数组
        for(int i=1; i<=n; i++){
            numbers.add(i);
        }
        k--;
        //这里是主要思路,来实现思路里说的情景
        for(int i = 1; i <= n; i++){
            int index = k/factorial[n-i];
            //找到这个 index 对应的下一个数字,添加到 StringBuilder 里面
            sb.append(String.valueOf(numbers.get(index)));
            numbers.remove(index);
            //把 k 减去 index*factorial[n-i],设置为下个循环部分里面对应的 k 的值
            k-=index*factorial[n-i];
        }
        return String.valueOf(sb);
    }

你可能感兴趣的:(每天一题LeetCode【第42天】)