zoukankan      html  css  js  c++  java
  • 60. Permutation Sequence (String; Math)

    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.

    思路:

    本题不像Permutation,不要求罗列所有permutation,所以没必要用回溯递归。

    本题如果用Next Permutation,会导致超时。需要寻找规律。

    规律:在n!个排列中,除去第一位,后几位共有(n-1)!个排列,所以第一位的元素总是(n-1)!一组出现的。那么,第k行第一位的值就=nums[(k-1)/(n-1)!]。

    依次类推第二位的值=nums[(k2-1)/(n-2)!],其中k2=(k-1)%(n-1)! Note: +1是因为k从1开始计数,而非0

    class Solution {
    public:
        string getPermutation(int n, int k) {
            string result = "";
            bool hasUsed[n+1]; //whether the number has used in the string
            for(int i = 0; i<=n; i++)
            {
                hasUsed[i] = false;
            }
            int dp[n]; //permutation number of a digit with i width = i!
            dp[0] = 1;
            dp[1] = 1;
            for(int i = 2; i< n; i++) 
            {
                dp[i] = i* dp[i-1]; //用动态规划法求阶乘
            }
            
            int num; //记录第i位的数字
            stringstream ss;
            string str;
            for(int i = n; i>0; i--)
            {
                num = k/dp[i-1];
                if(k%dp[i-1] != 0) num+=1;
                int counter = 0;
                int j;
                for(j = 1; j<=n && counter!=num; j++)
                {
                    if(!hasUsed[j])counter++; //如果这个数字已经出现,则不计数
                    if(counter == num) break;
                }
                hasUsed[j] = true;
                ss.clear(); 
                ss<<j;
                ss>>str;
                result += str;
                k = k-(num-1)*dp[i-1]; //该位的数字订了后,也就意味着已经处理一部分permutation number, 要把这部分去掉
            }
            return result;
        }
    };

     思路II:

    首先,不用把每个状态阶乘都存储,可以求出n! 然后每次遍历除以i便可以得到当前循环所需要的阶乘。

    其次,不需要flag,但设一个num[]记录还剩余的数字,这样的好处是,原先要做加法、赋值、比较操作,现在update num只需要赋值操作。

    class Solution {
    public:
        string getPermutation(int n, int k) {
            string result = "";
            vector<int> num; //num记录第i个数字是多少
            int factorial = 1; 
            for(int i = 0; i < n; i++){
                num.push_back(i+1); //给num赋初值
                factorial *= num[i]; //求阶乘(n-1)!
            }
    
            int index; //记录第i位的数字在num[]中的下标
            for(int i = n; i > 0; i--) //遍历每一位数字
            {
                factorial /= i; //update factorial
                index = (k-1)/factorial; //第n位数以(n-1)!为一组,按组出线;index表示第k行(从1开始计数)在第几组(从0开始计数)
                k = (k-1)%factorial +1; //update k
                result += ('0'+num[index]);
    
                for(int j = index; j+1 < i; j++) //update num
                {
                    num[j] = num[j+1];
                };
            }
            return result;
        }
    };
  • 相关阅读:
    .Net培训个人总结笔记28
    .Net培训个人总结笔记32
    .Net培训个人总结笔记21
    Codeforces Round #751 (Div. 1 & 2) Solutions
    「CEOI2017」Mousetrap 题解
    「CQOI2017」小Q的表格 题解
    mysql 非数字字段注意事项
    认识key及新鲜应用模式.
    B2C的革命: QQ网购
    php语言流程控制中的主动与被动.
  • 原文地址:https://www.cnblogs.com/qionglouyuyu/p/4870603.html
Copyright © 2011-2022 走看看