• [LeetCode] 60. Permutation Sequence


    The set [1,2,3,...,n] contains a total of n! unique permutations.

    By listing and labeling all of the permutations in order, we get the following sequence for n = 3:

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

    Given n and k, return the kth permutation sequence.

    Note:

    • Given n will be between 1 and 9 inclusive.
    • Given k will be between 1 and n! inclusive.

    Example 1:

    Input: n = 3, k = 3
    Output: "213"
    

    Example 2:

    Input: n = 4, k = 9
    Output: "2314"

    第K个排列。题意是给你一个数字N(比如N = 3),如果输出1到N的全排列,结果会是类似这样,

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

    现在给你一个数字N和一个数字K,请你输出的是这个全排列里面的第K项。

    我参考了LC讨论区的最高票答案。他的思路基本上是逐位确定每一位上应该是什么数字,然后再一点点append起来的。首先如果N = 4,那么也就是有1,2,3,4四个数字,他的permutation应该类似如下这样,同时4的全排列的总数是4! = 24

    • (0)1 + {2, 3, 4的全排列} = 6
    • (1)2 + {1, 3, 4的全排列} = 6
    • (2)3 + {1, 2, 4的全排列} = 6
    • (3)4 + {1, 2, 3的全排列} = 6

    如果给你一个数字N,你很容易就知道这N个数字的全排列的个数是N!。同时如果你知道全排列里面第一个数字的话,那么你接下来也只需要在(N - 1)! 个结果中就能确定你这个全排列到底是什么了。这月就是为什么这个题能逐位确定每一位上应该是什么数字的原因。

    还是假设N = 4,那么全排列的个数是4! = 24;如果你能确定第一个数字的话,那么你可以将要找的范围缩小到三个数字的全排列,即3! = 6。但是如何得知第一个数字呢?假如你要找的K = 14,先将K--,得到13(因为数组中的index一般是从0开始的)。K / (N - 1)! = K / 3! = 13 / 3! = 13 / 6 = 2,意味着第一个数字的index = 2,也就意味着第一个数字其实是3

    知道第一个数字是3之后,也就知道了接下来是在{1, 2, 4的全排列}里面找结果了。如果一直递归地往下想,要找的也就是

    (0)1 + {2, 4的全排列} = 2

    (1)2 + {1, 4的全排列} = 2

    (2)4 + {1, 2的全排列} = 2

    但是此时K已经不是13了,而是K % (N - 1)! = 13 % 3! = 13 / 6 = 1。

    下一轮K / (N - 1)! = 1 / 2! = 1 / 2 = 0,意味着第二个数字的index = 0,第二个数字是1是在1 + {2, 4的全排列}里面接着找。此时K = K % (N - 1)! = 1 % 2! = 1 % 2 = 1。

    此时在3 + {1, 2, 4的全排列}里面继续找。既然K = 0,那么在3 + 1 + {2, 4的全排列}里面的index又是多少呢?

    第三个数字的index = K / (N - 1)! = 1 / 1! = 1,意味着第三个数字的index = 2第三个数字是1,下一轮因为只剩一个数字2,所以结果就是3142。

    时间O(n^2)

    空间O(n)

    Java实现

     1 class Solution {
     2     public String getPermutation(int n, int k) {
     3         List<Integer> res = new ArrayList<>();
     4         for (int i = 1; i <= n; i++) {
     5             res.add(i);
     6         }
     7         int[] fact = new int[n];
     8         fact[0] = 1;
     9         for (int i = 1; i < n; i++) {
    10             fact[i] = i * fact[i - 1];
    11         }
    12         // [1, 1, 2, 6]
    13         k = k - 1;
    14         StringBuilder sb = new StringBuilder();
    15         for (int i = n; i > 0; i--) {
    16             int index = k / fact[i - 1];
    17             k = k % fact[i - 1];
    18             sb.append(res.get(index));
    19             res.remove(index);
    20         }
    21         return sb.toString();
    22     }
    23 }

    LeetCode 题目总结

  • 相关阅读:
    如何快速生成数据文件(fsutil命令,使用CreateFile和SetEndOfFile API函数,fopen和fseek RTL函数)
    TestDisk 数据恢复 重建分区表恢复文件-恢复diskpart clean
    利用winIO3.0进行windows10 64bit端口读取
    一个字体,大小,颜色可定义的自绘静态框控件-XColorStatic 类(比较好看,一共19篇自绘文章)
    美国富人与穷人的四个决定性差别!(冒风险、交朋友、敬业、生活习惯好)
    WebRTC 音视频开发
    协程的理解
    线程、进程、协程和队列
    Confluent
    “Options模式”下各种类型的Options对象是如何绑定的?
  • 原文地址:https://www.cnblogs.com/cnoodle/p/13171282.html
Copyright © 2020-2023  润新知