博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
60. Permutation Sequence
阅读量:4982 次
发布时间:2019-06-12

本文共 4503 字,大约阅读时间需要 15 分钟。

题目:

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 (ie, 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.

链接:  

题解:

数学题,找到第k个permutation sequence。 (题外话 : 现在经常体会到数学学得不够好会有多吃力,但也不必要为了钻牛角尖去做个数学家,要足够好,够用就可以了。但怎样算足够好,怎样算够用,很难界定啊。)

n!可以被分为n组,每组有(n - 1)!个数字。 假设k在1 ~ n!的范围内,则凭借k / (n - 1)! 我们可以从找到k中有多少组(n - 1)!,而 k %= (n - 1)!则可以把k映射到 1 ~ (n - 1)!的范围内,我们可以继续使用k / (n - 2)!来找到第二大的数字,以此类推。需要思考的地方是使用一个有效的数据结构,来获得当前的最大数字,以及所剩下最小的数字。我觉得可以使用min heap。 这里因为n为1 ~ 9,为简便使用了linkedlist。

还有一个很巧妙的地方是 k--,这样k / (n - 1)!就对应着从0 ~ (n - 1)这n个group,这个结果也是我们linkedlist中取出元素的index。接下来进行 k % = (n - 1)!后, k又继续对应 0 ~ (n - 2)这个 n - 1个group。非常好用。

Time Complexity - O(n), Space Complexity - O(n)。

public class Solution {    public String getPermutation(int n, int k) {        if(n <= 0)            return "";        List
list = new LinkedList
(); int factorial = 1; for(int i = 1; i <= n; i++) { list.add(i); factorial *= i; } k--; // crucial step, put k into range 0 - (n! - 1) StringBuilder sb = new StringBuilder(); while(n > 0) { // n digits factorial /= n; //get (n - 1)!; sb.append(list.remove(k / factorial)); // k / factorial = most important digits k %= factorial; // k % factorial = reflect k to range 0 - ((n - 1)! - 1) n--; } return sb.toString(); }}

 

二刷:

二刷的作用,就是清理一刷糊弄过去的题目。这道题目也是卡。 主要还是参考了discuss里面Adeath以及melvin.ming.gong的解答。以下的解释很烂,三刷希望总结得好一点。

思路主要是,我们有1 ~ n个字母可以来做全排列,那么假设k是存在于 1到 n!中的一个数字,这个数字就会对应我们的一个全排列字母组合,也就是kth permutation sequence。

下面我们来分析一下全排列每个数字的构成:

  1. 假如k = n!,那么结果肯定是9876543421,最大的全排列。 最高位的确定是 (k- 1) / (9 - 1)!,就是最高位的数字,是由这个数字的排位k - 1 除以低一位的全排列可能性 (n - 1)!来确定的。
  2. 我们先从找到最大的全排列 factorial = n!, 
  3. 为什么要k - 1。 假设我们有一个linkedlist,这个list包含所有数字的集合 -  1, 2, 3, 4, 5, 6, 7, 8, 9。因为链表的开头是从0 开始, 我们每次从链表中移除的话,要shift一位。这样 k % (n - 1)!就可以被映射到到 0 到 (n - 1)!这块bucket里。否则我们还要判断 k % (n - 1)是否为0,写一些额外的code
  4. 当我们求出最高位的数字 n1之后,那么我们接下来要做的就是,在剩下的数字里,我们更新 factorial /= n, 然后找到在linkedlist里面位置是  k / factorial的数字,再将其移除就可以了。
  5. 最好加上一些判断,比如 k <= 0的情况, 或者k > n!的情况。

Java:

Time Complexity - O(n2), Space Complexity - O(n)。   O(n2)因为我们用到了linekedlist的remove。假如 n属于 1 ~ 9的话其实可以认为是O(1), O(1)。

public class Solution {    public String getPermutation(int n, int k) {        if (k <= 0) {            return "";        }        List
nums = new LinkedList<>(); int factorials = 1; for (int i = 1; i <= n; i++) { nums.add(i); factorials *= i; } while (k > factorials) { if (k % factorials == 0) { k = factorials; } else { k %= factorials; } } StringBuilder sb = new StringBuilder(); for (k--; n > 0; n--) { factorials /= n; sb.append(nums.remove(k / factorials)); k %= factorials; } return sb.toString(); }}

 

三刷:

遇到这题还是会卡一点。应该是因为以前思路不够清晰吧。

我们主要是使用以下几个步骤:

  1. 先求得[1, n]的factorial, 同时创建一个linkedlist,node分别为[1, n]
  2. k--, 将k从 1-based转换为0-based,方便以后我们的模操作。
  3. 这里可以加一步判断,假如k >= n那么我们返回一个特定的字符串。
  4. 在n > 0的时候
    1. 我们先把factorial减少到(n - 1)!
    2. 然后我们计算k 中有多少个(n - 1)!,把这个数字作为linkedlist中的index找到相应的节点,删除这个节点并且将其值加到sb中
    3. 使用 k % factorial将 k映射到 (n - 1)!的范围内
    4. n--, 继续下一次操作。
  5. 返回结果sb.toString();

Java:

Time Complexity - O(n), Space Complexity - O(n)。  其实因为n只在1 ~ 9中,所以我们可以假定时空间复杂度都是O(1)

public class Solution {    public String getPermutation(int n, int k) {        if (k <= 0 || n <= 0) return "";        List
nums = new LinkedList<>(); int factorial = 1; for (int i = 1; i <= n; i++) { factorial *= i; nums.add(i); } StringBuilder sb = new StringBuilder(); k--; while (n > 0) { factorial /= n; sb.append(nums.remove(k / factorial)); k %= factorial; n--; } return sb.toString(); }}

 

 

Reference:

https://leetcode.com/discuss/16064/an-iterative-solution-for-reference

https://en.wikipedia.org/wiki/Lehmer_code

https://en.wikipedia.org/wiki/Permutation

https://leetcode.com/discuss/42700/explain-like-im-five-java-solution-in-o-n 

转载于:https://www.cnblogs.com/yrbbest/p/4436392.html

你可能感兴趣的文章
软件工程——理论、方法与实践⑦
查看>>
商品评论
查看>>
【转】Android 组件系列-----Activity保存状态
查看>>
批处理实现多线程执行命令列表文件
查看>>
跟牛牛老师学习python自动化的第六天
查看>>
利用Flume将本地文件数据中收集到HDFS
查看>>
html5的优缺点
查看>>
Vim 加 Gmail 变身 Vmail
查看>>
P1294 高手去散步
查看>>
一次谷歌面试趣事
查看>>
(5) Orchard 开发之 Localization and NullLocalizer
查看>>
分类算法(1)--KNN
查看>>
每日记载内容总结3
查看>>
ajax等待请求
查看>>
Java学习之equals和hashcode的关系
查看>>
一页纸商业计划书 (Business Plan) 模板(转载)
查看>>
什么是html
查看>>
妙用python之编码转换
查看>>
hdu 4451 Dressing 衣服裤子鞋 简单容斥
查看>>
TTTTTTTTTTTT Gym 100818B Tree of Almost Clean Money 树连剖分+BIT 模板题
查看>>