版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/afei__/article/details/82951905
题目
这是《算法导论 第3版》第二章的第 4 个思考题。
原题为:
假设 A[ 1…n ] 是一个有 n 个不同数的数组。若 i < j 且 A[ i ] > A [ j ] ,则对偶 (i, j) 称为 A 的一个逆序对。
给出一个确定在 n 个元素的任何排列中逆序对数量的算法,时间复杂度 O(n * lg n)。
(提示:修改归并排序)
分析
首先有一种直观的解法,即依次遍历数组 A,找出元素 A[ i ] 后面存在几个小于它的数,统计总次数即可。然而这种解法虽然简单,但时间复杂度为 O(n^2),代码也很简单这里不作示例了。下面说收怎么使用归并排序的方法计算逆序对的数量。
在归并阶段存在多少逆序对时,总有:逆序对数量 = 左半部分逆序对 + 右半部分逆序对 + 合并部分逆序对。
关键是怎么得到合并部分的逆序对数量,合并时,若 i 为左半数组的遍历索引,j 为右半数组的遍历索引,一旦发现 A [ i ] 比 A [ j ] 大,那么会有 ( mid – i ) 个逆序对产生。因为 A [ i + 1 ] , A [ i + 2 ] … A [ mid - 1 ] 都比 A [ j ] 大。其中 mid 是右半数组开始的索引。
解答
public class Main {
public static void main(String[] args) {
int[] arr = new int[] { 2, 3, 8, 6, 1 };
int inversionCount = mergeSort(arr, 0, arr.length);
printArray(arr);
System.out.println("inversionCount: " + inversionCount);
}
public static int mergeSort(int[] arr, int start, int end) {
int inversionCount = 0;
int length = end - start;
if (length > 1) { // 长度大于1才需要排序
int mid = (start + end) / 2;
inversionCount += mergeSort(arr, start, mid); // sort left
inversionCount += mergeSort(arr, mid, end); // sort right
inversionCount += merge(arr, start, mid, end);
}
return inversionCount;
}
public static int merge(int[] arr, int start, int mid, int end) {
// check input
if (arr == null || start < 0 || end > arr.length) {
return 0;
}
int[] temp = new int[end - start];
int inversionCount = 0;
int i = start; // 左半部分索引
int j = mid; // 右半部分索引
int k = 0; // temp数组索引
while (i < mid && j < end) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
// 一旦 arr[i] > arr[j],就会有 (mid - i) 个逆序对产生
inversionCount += mid - i;
}
}
if (i != mid) {
System.arraycopy(arr, i, temp, k, mid - i);
}
if (j != end){
System.arraycopy(arr, j, temp, k, end - j);
}
System.arraycopy(temp, 0, arr, start, temp.length);
return inversionCount;
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
运行结果:
扫描二维码关注公众号,回复:
3491121 查看本文章
1 2 3 6 8
inversionCount: 5
原数组为 [ 2, 3, 8, 6, 1 ],其逆序对有 (2, 1)、 (3, 1)、 (8, 1)、 (6, 1)、 (8, 6) 共 5 对。
符合我们运行结果。