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