题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。链接
归并排序的过程中计数
class Solution {
private int[] temp;
//辅助数组,存放每段归并数组
private int[] nums;
public int reversePairs(int[] nums) {
int len = nums.length;
if (len < 2) {
return 0;
}
temp = new int[len];
this.nums = Arrays.copyOf(nums, len);
return helper(0, len - 1);
}
/**
* 分治
*/
private int helper(int left, int right) {
if (left == right) {
return 0;
}
//此处为向下取整
int mid = left + (right - left) / 2;
int leftPair = helper(left, mid);
int rightPair = helper(mid + 1, right);
//mid小于mid+1时此时已经有序,不需要再合并计数
if (nums[mid] <= nums[mid + 1]) {
return leftPair + rightPair;
}
int cross = mergeCount(left, mid, right);
return leftPair + rightPair + cross;
}
/**
* 归并nums[left,mid]与nums[mid+1,right]的同时计数
* */
private int mergeCount(int left, int mid, int right) {
for (int i = left; i <= right; i++) {
temp[i] = nums[i];
}
int i = left, j = mid + 1;
int count = 0;
for (int k = left; k <= right; k++) {
//temp[left,mid]已经归并完
if (i == mid + 1) {
nums[k] = temp[j];
j++;
}//[mid+1,right]已经归并完
else if (j == right + 1) {
nums[k] = temp[i];
i++;
} else if (temp[i] <= temp[j]) {
nums[k] = temp[i];
i++;
}//[j,right]中有小于temp[i]的,归并后加上[i,mid]的元素个数
else {
nums[k] = temp[j];
j++;
count += mid - i + 1;
}
}
return count;
}
}