题目大意:给出n和k,找到1..n这些数组成的有序全排列中的第k个。

 

首先,n的全排列可以分成n组,每一组由n-1个数组成。

例如  3的全排列,分成三组:

1  2  3  和 1  3  2

2  1  3  和 2  3  1

3  1  2  和 3  2  1

每一组的个数是(n-1)!,每一组的打头的都是i 。第i组以i打头。

先求 x = (k-1) / (n-1)!  + 1

比如  n = 3, k = 4.

x = 3/2 + 1 = 2,得到 第四个实际上第二组里面。

y = (k-1)%(n-1)! + 1 = 2,即,要求的东西在第二组的第二个数。

 

第二组的特征是,以2开头。所以我们找到第2个数,放到string ans的最高位置。

 

然后,求剩下的数里面的全排列的第y个。 即把2去掉,用1 和 3做全排列,取其中的第2个。

这时候,回到初始的步骤。递归即可。

 

垃圾的代码,现在脑子懵。。写的代码跟屎一样,完全没有逻辑啊!要优化!!

 

class Solution {
public:
    int factorial(int n)            //计算n的阶乘
    {
        if(n == 1 || n == 0) return 1;
        return n*factorial(n-1);
    }
    
    void back_track(vector<int>&used, string &ans, int n, int cnt, int k)    //cnt表示ans里有几个元素。找到第k个。
    {
        if(cnt == n)  return;     //所有的都用完了
        
        int fac = factorial(n-1-cnt);       //初始是n-1
        
        int x = (k-1)/fac + 1;   //在第x 个序列  第一个数是第几个
        k = (k-1)%fac + 1;       //x序列的第k个
        
        int i,j;
        
        i = 1;
        
        while(used[i]) i ++;        //找到第一个没用过的元素
        for(j = 1; j < x;i++)       //这时候x指向的是第1个未使用的元素
        {
            if(!used[i]) j++;       //此时x走过了j-1个元素。
        }
        while(used[i]) i++;         //找到第x个未使用的元素
        
        ans.append(1,i + '0');      //把这个元素放在头
        used[i] = true;             //这个元素被使用了
        back_track(used, ans, n, cnt + 1,k);        //用剩下的去构造第k个元素
    }
    string getPermutation(int n, int k) {
        int i;
        vector<int> used(n+1,false);
        string ans;
        back_track(used,ans,n,0,k);
        return ans;
    }
    
};

 

posted on 2017-12-10 16:48  newbird2017  阅读(145)  评论(0编辑  收藏  举报