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;
    }
};

 

posted on 2015-10-12 06:29  joannae  阅读(193)  评论(0编辑  收藏  举报

导航