1.歸併排序
- 歸併排序是分治法的一種典型應用,應用遞歸思想,自頂向下思考:先假定
MergeSort()
可以將一個亂序數組排好序,因此可以開始分
(將一個數組平均分成兩部分),再治
(分別調用MergeSort()
使前後兩部分有序),最後使用Merge()
將兩個有序數組合併爲一個有序數組。
Merge()
方法實現簡單,只需管理兩個指針,分別指向待合併的兩個數組,開闢輔助數組保存中間結果,O(n)
時間複雜度即可完成
2.逆序數
- 逆序數的定義:如果
i < j
且A[i] > A[j]
.則A[i]
和A[j]
即爲逆序數對.逆序數對的個數就叫逆序數
- 求逆序數可以通過管理兩個指針,兩次掃描數組,蠻力法求出,顯然時間複雜度是
Θ(n^2)
.
- 利用歸併排序法,稍做改進即可.在
Merge()
中,合併兩個已經有序的數組A,B.因爲A.B有序,所以,A,B各自的逆序數是0,所以AB的逆序數等於A,B之間的逆序數.
- 舉個例子:
A=1,4,6,7,9
,B=2,3,5,10,13,21
.在Merge中發現當前i號元素4比2大,那麼4的逆序數需要+1,又因6,7,9都排在4後面,那麼6,7,9的逆序數也應該+1,所以總體的逆序數應該加上last-i+1
.
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
public int InversePairs(int[] array) {
int len = array.length;
int[] c = new int[len];
count = 0;
MergeSort(array, 0, len - 1, c);
return count;
}
public static int MOD = 1000000007;
public static int count = 0;
public static void Merge(int[] array, int left, int mid, int right, int[] c) {
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (array[i] <= array[j])
c[k++] = array[i++];
else {
c[k++] = array[j++];
count = (count + mid - i + 1) % MOD;
}
}
while (i <= mid)
c[k++] = array[i++];
while (j <= right)
c[k++] = array[j++];
for (int in = left; in <= right; in++) {
array[in] = c[in];
}
}
public static void MergeSort(int[] array, int left, int right, int[] c) {
if (left < right) {
int mid = (left + right) / 2;
MergeSort(array, left, mid, c);
MergeSort(array, mid + 1, right, c);
Merge(array, left, mid, right, c);
}
}
}