領釦編程:排列序號

問題描述:
給出一個不含重複數字的排列,求這些數字的所有排列按字典序排序後該排列的編號。其中,編號從1開始。

樣例
樣例 1:

輸入:[1,2,4]
輸出:1
樣例 2:

輸入:[3,2,1]
輸出:6

思路:

  1. 按原始思路套,多層遍歷,逐個比較,但是數字數量大的時候性能消耗大。

  2. 可研究規律,作如下算法:

    1. 設給定輸入序列A,拷貝序列A至序列B(以vector裝載)
    2. 從A中取出第一個數據a
    3. 對B排序
    4. 確認a在B中對應的下標
    5. 設B的大小爲m,求出n*(m-1)!
    6. 然後從B中刪除a
    7. 從A中取出下一個數據a
    8. 回到3,直到B的大小爲1
    9. 最後將每次求出的值累加起來並加1,即所求的值

    上述爲何是n*(m-1)! 呢? 因爲對於a來說,a對應B的下標n,說明有n個小於a的值存在,那麼以這些小於a的值爲頭的都是排在a爲頭的前面的,每個值對應有(m-1)! 個排列,一共有n個,所以爲n*(m-1)!。這些都需要統計出來。後續從B中刪除a後又相當於重複上一輪流程。

class Solution {
public:
    /**
     * @param A: An array of integers
     * @return: A long integer
     */
    long long permutationIndex(vector<int> &A) {
        // write your code here
        // 拷貝一個臨時副本
        vector<int> B = A;
        
        // 思路:
        /*
        對B排序,然後根據按順序取A中的數據,每次取出一個A的數據a時,先對B排序,然後確認
        a對應B的下表n,設B的大小爲m,求出n*(m-1)!,然後刪除B中的a,再排序,如此循環,最後將
        結果累加並加1,即爲所求值
        */
        long long lRet = 0;
        while(B.size() > 1)
        {
            // 從小到達排序
            std::sort(B.begin(), B.end());
            // 取得A中第一個數字在B中的下表
            int i = 0;
            auto iter = B.begin();
            while(iter != B.end())
            {
                if(A[A.size() - B.size()] == *iter)
                {
                    lRet += i * Calculate(B.size() - 1);
                    B.erase(iter);
                    break;
                }
                i++;
                iter++;
            }
        }
        
        return lRet + 1;
    }
    
    long long Calculate(size_t n)
    {
        long long llRet = 1;
        while(n > 0)
        {
            llRet *= n;
            n--;
        }
        return llRet;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章