參考:一、 https://www.geeksforgeeks.org/merge-sort/面試
二、《劍指Offer:名企面試官精講典型編程題》編程
在數組中的兩個數字,若是前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007數組
題目保證輸入的數組中沒有的相同的數字ide
數據範圍:spa
示例1 輸入:1,2,3,4,5,6,7,0 輸出:7
這個方法最簡單直接,順序掃描整個數組,每掃到一個數,逐個比較其後面的全部數,若是構成逆序對,則計數+1。代碼沒啥難度,略了。指針
1 public int InversePairs(int[] array) { 2 if (array.length < 2) { 3 return 0; 4 } 5 return divideAndConquer(array, 0, array.length); 6 } 7 8 public int divideAndConquer(int[] array, int l, int r) { 9 if (l >= r - 1) return 0; 10 11 int mid = (l + r) / 2; 12 int count = 0; 13 int countL = divideAndConquer(array, l, mid); 14 int countR = divideAndConquer(array, mid, r); 15 int[] left = Arrays.copyOfRange(array, l, mid); 16 int[] right = Arrays.copyOfRange(array, mid, r); 17 int i = left.length - 1; 18 int j = right.length - 1; 19 for (int k = r - 1; k >= l; k--) { 20 // two cases: left is empty or right is empty 21 if (i < 0) { 22 array[k] = right[j]; 23 j--; 24 continue; 25 } else if (j < 0) { 26 array[k] = left[i]; 27 i--; 28 continue; 29 } 30 if (left[i] > right[j]) { 31 count += j + 1; 32 if (count > 1000000007) { 33 count %= 1000000007; 34 } 35 array[k] = left[i]; 36 i--; 37 } else { 38 array[k] = right[j]; 39 j--; 40 } 41 } 42 return (count + countL + countR) % 1000000007; 43 }
這一題的解法是在歸併排序(Merge Sort) 的基礎上修改獲得的。Merge Sort使用的是分治法的思想。分治法 (divide and conquer) 是將一個複雜的問題,分紅兩個或多個相同或者類似的子問題,再把子問題分紅更小的子問題,一直分到子問題足夠簡單來求解,最後再把子問題的解合併成原問題的解。歸併排序法的時間複雜度爲 O(nlogn),空間複雜度爲 臨時的數組 + 遞歸時壓入棧的數據佔用的空間 = n + logn,即 O(n)。code
以數組 {7, 5, 6, 4} 爲例進行分析,解題過程如圖5.2所示。首先將數組拆成至長度爲1的子數組,而後一邊合併一邊統計逆序對的數目。在第一對長度爲1 的子數組 {7}、{5}中,有一對逆序對 (7, 5)。在第二對長度爲1的子數組 {6}、{4}中,也有一對逆序對(6, 4)。在統計完這兩對逆序對後,須要分別對他們進行排序,如圖 5.2(c),以避免在之後的統計過程當中再重複統計。blog
而後須要統計兩個長度爲2的子數組之間的逆序對,併合並兩個子數組,如圖5.3所示。兩個子數組分別從末尾開始判斷數的大小,如圖5.2(a)中指針P一、P2。若是 P1 大於 P2,則構成逆序對,而且逆序對的數目等於第二個子數組中剩餘數字的個數,即 P2 以及以前的全部數字的個數。若是 P1 小於或等於 P2, 則不構成逆序對。每次比較的時候,咱們都把較大的數字從後往前複製到一個輔助數組,確保輔助數組中的數字是遞增排序的。在把較大的數字複製到輔助數組以後,把對應的指針向前移動一位,接下來進行下一輪比較。排序
以此類推,使用這個方法去求出其餘數組的逆序對個數。在解這一題的時候,還有一點須要注意,除了須要將總輸出結果 (count + countL + countR) 對1000000007取模,還要在計算過程當中將 count += j + 1 對1000000007取模,以避免count超出 Integer.MAX_VALUE。遞歸