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);
}
}
}