題目:在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數p。並將p對1000000007取模的結果輸出。 即輸出p%1000000007。
題目保證輸入的陣列中沒有的相同的數字
資料範圍:
對於%50的資料,size<=10^4
對於%75的資料,size<=10^5
對於%100的資料,size<=2*10^5
1,2,3,4,5,6,7,0 結果是 7
一看到這個題我就感覺似曾相識,知道需要使用歸併排序的思想來做,卻早已忘記了歸併排序的思想到底是什麼。。。於是特地整理了一遍,見部落格歸併排序演算法。
在歸併排序的歸併步驟時,可以順便統計逆序對的個數。
假設正在歸併上面的陣列,左側的2,3,6,8
和右側的1,4,5,7
已經排好序了,左側和右側內部都沒有逆序對,而從左側取乙個數,從右側取乙個數,則有可能形成逆序對。
例如,開始左側拿出2
,右側拿出1
,可知2>1
,形成了逆序對。此時逆序對只是加1
嗎?並不是,因為2
右邊的數都是大於2
的,所以可以判斷左邊的數和右邊的1
可以形成4
對逆序對((2,1)、(3,1)、(6,1)、(8,1))。
接下來比2
和4
,不會形成逆序對。再比3
和4
,不會形成逆序對。
當比較到6
和4
的時候,形成了逆序對,個數為2
((6,4)、(8,4))。
歸納一下,也就是在歸併的時候,如果右側的元素小於左側的元素,這個時候開始統計逆序對就行了,如果左側的索引為i
,左側的末尾元素的索引為mid
,逆序對個數就為mid-i+1
。
這樣並沒有結束,前面的假設是左側和右側是有序的,事實上並不是,左側和右側也進行了歸併的過程才能變得有序,而在歸併過程中,也能計算出逆序對的個數。
所以:總的逆序對的個數=左側歸併時求得的逆序對個數 + 右側歸併時求得的逆序對個數 + 對整體進行歸併時的逆序對個數。
可能會懷疑這三種情況會有重複,但是並沒有。左側歸併找到的逆序對相當於從左側陣列中取2
個數,而整體歸併的時候是分別從左右陣列中取1
個數,不可能發生重複!
知道上面的思路後,可以很容易的將歸併排序**進行修改。
class solution
int mergesort(vector&arr, vector&aux)
// [l, r]
int __mergesort(vector&arr, vector&aux, int l, int r)
int __merge(vector&arr, vector&aux, int l, int mid, int r)
else if( j > r )
else if( aux[i] < aux[j] )
else
}return res;}};
求逆序對是對歸併排序思想的經典應用,很巧妙。求逆序對好像還有樹狀陣列的方法,精力不夠,掌握一種方法足夠了。
劍指offer第二版--面試題51
歸併排序演算法
劍指offer 逆序對
這道題隱含的思想是二分法和歸併排序。class solution long long inversepairscore vector data,vector int start,int end int length end start 2 long long left inversepairscor...
劍指offer刷題
面試題6 從尾到頭列印鍊錶 struct listnode class solution reverse res.begin res.end return res 替換空格class solution int newnumstr numstr numspace 2 if newnumstr leng...
劍指offer刷題
原題鏈結 動態規劃 class solution dp for int i 1 i len1 i else if p j 1 else return dp len1 len2 原題鏈結 數學推導 找規律 class solution else if n 3 2 return ipow 3 numso...