import java.util.*;
public class Solution {
// 思路:归并排序的思想,分治之后排序合并
public int mod = 1000000007;
public int mergeSort(int left, int right, int[] nums, int[] temp) {
if (left >= right) {
return 0;
}
int mid = (left + right) / 2;
// 递归分治,左右划分合并
// 划分阶段:将带划分区间从中点划分成两部分,两部分进入递归继续划分,直到子数组长度为1
// 排序逻辑处理
// 排序阶段:使用归并排序递归处理逆序对,因为在归并排序中,我们会依次比较相邻两组子数组各个元素的大小,并累计遇到的逆序情况。而对排好序的两组,右边大于左边时,它大于了左边的所有子序列,基于这个性质我们可以不用每次加1来统计,减少运算次数。
int res = mergeSort(left, mid, nums, temp) + mergeSort(mid + 1, right, nums, temp);
// 防止溢出
res %= mod;
// ---------------
int i = left, j = mid + 1;
for (int k = left; k <= right; k++) {
// temp用于临时保存nums的值,防止丢失
temp[k] = nums[k];
}
// 合并阶段使用双指针,来比较并合并两个已排序的子数组
for (int k = left; k <= right; k++) {
// i == mid + 1用于检测左子数组是否已经检测完毕
if (i == mid + 1) {
nums[k] = temp[j++];
} else if (j == right + 1 || temp[i] <= temp[j]) {
nums[k] = temp[i++];
// 左边比右边大,答案增加
} else {
nums[k] = temp[j++];
// 当左子数组的元素 temp[i] 大于右子数组的元素 temp[j] 时,temp[i] 及其后面的所有元素(从 i 到 mid)都与 temp[j] 构成逆序对,因此逆序对数量增加 mid - i + 1。
res += mid - i + 1;
}
}
return res % mod;
}
public int InversePairs (int[] nums) {
// write code here
int n = nums.length;
int[] res = new int[n];
return mergeSort(0, n - 1, nums, res);
}
}