【LeetCode】60.Permutation Sequence 輸出第k個排列

一、概述

輸入正整數n和k,輸出包含1~n共n個整數組成的排列中的第k個。

比如說n=3,則排列有123,132,213,231,312,321六個。k=3則輸出213。

我使用遞歸求解,很容易看懂,時間複雜度很好,空間複雜度還可以。

二、分析

n=3我們不容易看出來。我們以n=4爲例:

1234

1243

1324

1342

1423

1432

2134

2143

2314

2341

2413

2431

......

我們通過觀察可以發現,排列是按由小到大的順序確定的。一共就n個數,設置我們的“原料爲”1234。

共有n!=24個排列,其中,前(n-1)!=6個第一位爲1,(n-1)!+1到(n-1)!+(n-1)!個第一位爲2;以此類推。

也就是說,第一位我們可以通過k/(n-1)!進行向上取整求出,取出“原料”中的第ceil(k/(n-1)!)個,令loc1=ceil(k/(n-1)!)。原料變爲134。

那麼第二位有什麼規律呢?

將第一位爲2的單拿出來:

2134

2143

2314

2341

2413

2431

同樣的,共有(n-1)!個排列,其中,前(n-2)!=2個第二位爲1,(n-2)!+1到(n-2)!+(n-2)!個第二位爲3;以此類推。

第二位怎麼求呢?不容易直接看出來。可以這樣看:首先,我們要求所有排列的第k個,當我們將第一位a確定後,我們也就砍掉了第一位小於a的所有排列,即砍掉了(a-1)*(n-1)!個排列,同時我們得到了一個長度爲(n-1)!的新排列。那麼,我們就要求出新的排列中,我們要第幾個——第k-(loc1-1)*(n-1)!個,這就是新的k,如何由k確定要“原料”中的第幾個呢?ceil(k/(n-1)!)啊,具體到本例就是ceil((k-(a-1)*(n-1)!)/(n-2)!),設置其爲,也就是ceil((9-(2-1)*(4-1)!)/(4-2)!)=2,loc2=2。也就是3,原料變爲14。

將第一位爲2和第二位爲3的拿出來,新排列有(n-2)!個排列:

2314

2341

前(n-3)!=1個第三位爲1,然後是4。

第三位怎麼求呢?類似第二位,我們要確定新排列中我們要第幾個:第k-(loc1-1)*(n-1)!-(loc2-1)*(n-2)!=9-(2-1)*6-(2-1)*2=1,這就是新的k。那麼loc=ceil(k/(n-3)!)=1/1!=1。取出原料的第1個,原料剩餘4。

把4放在最後,得到結果。

用文字說明又複雜又難以理解,寫成式子就很容易看:

代碼如下:

class Solution {
    string res;
    int n_fact[11]={0,1,2,6,24,120,720,5040,40320,362880};
    void generate(string s,int k,int n)
    {
        if(s.size()==1)
        {
            res+=(s[0]);
            return;
        }
        else
        {
            int loc=ceil(k*1.0/n_fact[n-1]);
            res+=(s[loc-1]);
            s.erase(s.begin()+loc-1);
            generate(s,k-(loc-1)*n_fact[n-1],n-1);
        }
    }
public:
    string getPermutation(int n, int k) {
        string s;
        for(int i=1;i<=n;i++)
            s+=(i+'0');
        generate(s,k,n);
        return res;
    }
};

注意先將階乘計算出來保存在數組裏可以節約很多時間。

三、總結

手動算一算每一位是怎麼求出來的,就很容易發現規律。然後就迭代就好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章