• LeetCode: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 (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 是否小于1 或者 是否大于n!

    分析:按照一般的递归求全排列的算法(LeetCode:Permutations),输出的序列不是按字典序有序的,比如对于1,2,3,输出序列为:

    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 2 1
    3 1 2

    以3开头的排列举例,算法中是把1和3交换得到3 2 1,然后递归的求解,但是3 2 1不是以3开头的最小序列,应该是3 1 2. 为了得到有序的序列,我们不是把1 3 交换,而是应该把3移动到1的前面,这样得到的第一个以3开头的序列就是3 1 2。因此有如下的算法:

    算法1

     1 class Solution {
     2 private:
     3     int k_;
     4     string res_;
     5 public:
     6     string getPermutation(int n, int k) {
     7         k_ = k;
     8         string str = string("123456789").substr(0, n);
     9         int cnt = 0;
    10         PermutationRecur(str, 0, cnt);
    11         return res_;
    12     }
    13     
    14     bool PermutationRecur(string &str, int index, int &cnt)
    15     {
    16         int len = str.size();
    17         if(index == len - 1)
    18         {
    19             cnt++;
    20             if(cnt == k_)
    21             {
    22                 res_ = str;
    23                 return true;
    24             }
    25         }
    26         else
    27         {
    28             for(int i = index; i < len; i++)
    29             {
    30                 rotate(&str[index], &str[i], &str[i+1]);
    31                 if(PermutationRecur(str, index + 1, cnt))
    32                     return true;
    33                 rotate(&str[index], &str[i], &str[i+1]);
    34             }
    35         }
    36         return false;
    37     }
    38 };
    View Code

    该算法在大数据下超时了。


    算法2

    利用next_permutation函数(该函数的详解请参考LeetCode:Permutations算法3),这种做法也超时了

    1 class Solution {
    2 public:
    3     string getPermutation(int n, int k) {
    4         string str = string("123456789").substr(0, n);
    5         for(int i = 1; i <= k-1; i++)
    6             next_permutation(str.begin(), str.end());
    7         return str;
    8     }
    9 };
    View Code

    算法3                                                 

    上面的算法都是逐个的求排列,有没有什么方法不是逐个求,而是直接构造出第k个排列呢?我们以n = 4,k = 17为例,数组src = [1,2,3,...,n]。

    第17个排列的第一个数是什么呢:我们知道以某个数固定开头的排列个数 = (n-1)! = 3! = 6, 即以1和2开头的排列总共6*2 = 12个,12 < 17, 因此第17个排列的第一个数不可能是1或者2,6*3 > 17, 因此第17个排列的第一个数是3。即第17个排列的第一个数是原数组(原数组递增有序)的第m = upper(17/6) = 3(upper表示向上取整)个数。                                           本文地址

    第一个数固定后,我们从src数组中删除该数,那么就相当于在当前src的基础上求第k - (m-1)*(n-1)! = 17 - 2*6 = 5个排列,因此可以递归的求解该问题。

     1 class Solution {
     2 public:
     3     string getPermutation(int n, int k) {
     4         string str = string("123456789").substr(0, n);
     5         string res(n, ' ');
     6         for(int i = 0; i < n; i++)
     7             res[i] = helper(str, k);
     8         return res;
     9     }
    10     //以s中字符构造的全排列中,返回第k个排列的第一个字符,并且删除s中该字符
    11     //s中字符递增有序
    12     char helper(string &s, int &k)
    13     {
    14         int tmp = factorial(s.size()-1), i = (k-1)/tmp;
    15         char res = s[i];
    16         s.erase(i, 1);
    17         k -= i*tmp;//更新k
    18         return res;
    19     }
    20     //求正整数n的阶乘
    21     int factorial(int n)
    22     {
    23         int res = 1;
    24         for(int i = 2; i <= n; i++)
    25             res *= i;
    26         return res;
    27     }
    28 };

    当然也可以非递归实现

     1 class Solution {
     2 public:
     3     string getPermutation(int n, int k) {
     4         int total = factorial(n);
     5         string candidate = string("123456789").substr(0, n);
     6         string res(n,' ');
     7         for(int i = 0; i < n; i++)//依次计算排列的每个位
     8         {
     9             total /= (n-i);
    10             int index = (k-1) / total;
    11             res[i] = candidate[index];
    12             candidate.erase(index, 1);
    13             k -= index*total;
    14         }
    15         return res;
    16     }
    17     int factorial(int n)
    18     {
    19         int res = 1;
    20         for(int i = 2; i <= n; i++)
    21             res *= i;
    22         return res;
    23     }
    24 };

    【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3721918.html

  • 相关阅读:
    Latex 双栏模式下表格太长怎么办?
    HTTP状态码大全
    You can't specify target table 'Person' for update in FROM clause
    mysql实战笔记
    「2020年中总结」这半年我又做了哪些副业?
    Mysql导入数据报错SQL Error(1153)
    PS制作电子签名
    Windows Server 2012 R2安装mssql
    Windows Server 2012 R2安装.net3.5
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/TenosDoIt/p/3721918.html
Copyright © 2020-2023  润新知