使用二分归并思想,一个数组的逆序对的数量 = (构成逆序对的数字都在左半部分)左半部分逆序对的数量 + (构成逆序对的数字都在右半部分)右半部分逆序对的数量 + (构成逆序对的数字左半部分一个,右半部分一个)左右两部分的逆序对的数量。
Java代码如下:
public class Solution {
// 使用归并思想统计数组中的逆序对
public static int invertCount(int[] nums, int left, int right) {
if (left >= right) {
return 0;
}
int middle = (left + right) / 2;
// 整个序列的逆序数,等于左半部分的逆序数 + 右半部分的逆序数 + 左右构成的逆序数
int leftCount = invertCount(nums, left, middle);
int rightCount = invertCount(nums, middle + 1, right);
int both = merge(nums, left, middle, right);
return leftCount + rightCount + both;
}
// 归并过程
public static int merge(int[] nums, int left, int middle, int right) {
int invertNum = 0;
// 使用两个临时数组保存元素
int index = left;
int length1 = middle - left + 1;
int length2 = right - middle;
int[] num1 = new int[length1];
int[] num2 = new int[length2];
for (int i = 0; i < length1; i++) {
num1[i] = nums[index];
index++;
}
for (int i = 0; i < length2; i++) {
num2[i] = nums[index];
index++;
}
index = left;
// 归并过程
int first = 0;
int second = 0;
while (first < length1 && second < length2) {
if (num1[first] <= num2[second]) {
nums[index] = num1[first];
first++;
} else {
nums[index] = num2[second];
second++;
// 此时,num2中当前正处理的数字,和当前num1中的所有数字构成逆序
invertNum += (length1 - first);
}
index++;
}
if (first == length1) {
// 将num2剩余的数字全部赋值到nums数组中(这一过程,不需要逆序对统计工作)
while (second < length2) {
nums[index] = num2[second];
second++;
index++;
}
} else {
// 将num1剩余的数字全部赋值到nums数组中(这一过程,不需要逆序对统计工作)
while (first < length1) {
nums[index] = num1[first];
first++;
index++;
}
}
return invertNum;
}
public static void main(String[] args) {
// 逆序对数量应为3
int[] nums = { 3, 14, 1, 7 };
System.out.println(Solution.invertCount(nums, 0, nums.length - 1));
// 逆序对数量应为7
int[] nums2 = { 3, 14, 1, 7, 35, 52, 4 };
System.out.println(Solution.invertCount(nums2, 0, nums2.length - 1));
}
}