問題描述:
給出一個不含重複數字的排列,求這些數字的所有排列按字典序排序後該排列的編號。其中,編號從1開始。
樣例
樣例 1:
輸入:[1,2,4]
輸出:1
樣例 2:
輸入:[3,2,1]
輸出:6
思路:
-
按原始思路套,多層遍歷,逐個比較,但是數字數量大的時候性能消耗大。
-
可研究規律,作如下算法:
- 設給定輸入序列A,拷貝序列A至序列B(以vector裝載)
- 從A中取出第一個數據a
- 對B排序
- 確認a在B中對應的下標
- 設B的大小爲m,求出n*(m-1)!
- 然後從B中刪除a
- 從A中取出下一個數據a
- 回到3,直到B的大小爲1
- 最後將每次求出的值累加起來並加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;
}
};