刷題 劍指offer之逆序對的個數

2021-09-13 12:42:14 字數 1884 閱讀 1953

題目:在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數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))。

接下來比24,不會形成逆序對。再比34,不會形成逆序對。

當比較到64的時候,形成了逆序對,個數為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...