题目的意思可以简化为:对于数组中的某个元素,统计在他之前比它大的元素的个数。对所有每个元素进行统计并累加后即为答案。
因此首先可以想到使用两层循环遍历数组,但该方法超时。
然后可以想到采用分治的思想,使用归并排序来实现逆序对的计算。通过归并排序,我们可以先对仅有1个元素组成的子数组中的逆序对进行计算,显然此时为0,然后将各个子数组排好序后,再将2个子数组合并为一个子数组。
由于合并时每个子数组时有序的,而且排序过后,两个子数组间的相对位置仍保持与排序前的一致,这点非常重要,这说明子数组的排序不会影响在两个子数组之间的逆序对的数量。在合并的过程中再统计跨越两个子数组间的逆序对的数量。
/**
** 归并排序的基本框架
**/
class Solution {
int count=0;
public int reversePairs(int[] nums) {
int[] temp = new int[nums.length];
sort(nums, 0, nums.length-1, temp);
return count;
}
public void sort(int[] nums, int left, int right, int[] temp){
if(left>=right){
return;
}
int mid = left + (right - left)/2;
sort(nums,left,mid,temp);
sort(nums,mid+1,right,temp);
merge(nums,left,mid,right,temp);
}
public void merge(int[] nums, int left, int mid, int right, int[] temp){
int l = left;
int r = mid+1;
int t = 0;
while(l<=mid && r<=right){
if(nums[l] <= nums[r]){
temp[t++] = nums[l++];
//合并连个子数组时对逆序对进行计算
count += r-(mid+1);
}else{
temp[t++] = nums[r++];
}
}
while(l<=mid){
temp[t++] = nums[l++];
count += r - (mid+1);
}
while(r<=right){
temp[t++] = nums[r++];
}
t=0;
while(left<=right){
nums[left++] = temp[t++];
}
}
}