题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入 : [7,5,6,4]
输出 : 5
限制: 0 <= 数组长度 <= 50000
思路
采用归并排序的方法来解:
归并排序就是将一个数组,二二分,直到分不下去了,再往回有序合并。
逆序对的判断在归并排序中的归并中:
左:1 3 5 7 | 右: 2 4 6 8
总:
1 2(此时有三对逆序对(3,2)(5,2)(7,2))
3 4 (此时有两对逆序对(5,4)(7,4))
5 6 (此时有一对逆序对(7,6))
7 8
当把右边的数往上放时,左边还剩几个,就有几个逆序对
举例:
1 3 7 5 4 2 6 8
1 3 7 5 | 4 2 6 8
1 3 | 7 5 | 4 2 | 6 8
->
1 3 | 5 7 | 2 4 | 6 8 这层逆序对为2个 (7,5)(4,2)
1 3 5 7 | 2 4 6 8 这层逆序对为 0个
1 2 3 4 5 6 7 8 这层逆序对为 6个
class Solution {
public:
int reversePairs(vector<int>& nums) {
int len = nums.size();
if(len<2) return 0; //如果小于2,也根本不会有逆序对出现
int temp[len]; //避免每次都申请数组,占空间
return mergeSort(nums,0,len-1,temp);
}
int merge(vector<int>& nums,int left,int mid,int right,int temp[]){
for(int i=left;i<=right;i++){ //将原数组复制给temp
temp[i]=nums[i];
}
int i=left,j=mid+1;
int sum=0;
for (int k = left; k <= right; k++) {
if (i == mid+1) { //左边都归并完了
nums[k] = temp[j++];
} else if (j == right + 1) { // 右边都归并完了
nums[k] = temp[i++];
} else if (temp[i] <= temp[j]) { //左边小
nums[k] = temp[i++];
} else { // 右边小
nums[k] = temp[j++];
sum += (mid - i + 1);
}
}
return sum;
}
int mergeSort(vector<int>& nums,int left,int right,int temp[]){
if(left<right){
int mid = left+(right-left)/2;
int l = mergeSort(nums,left,mid,temp);
int r = mergeSort(nums,mid+1,right,temp);
if(nums[mid]<=nums[mid+1]){//如果左右两个数组自动有序,就不用再合并了
return l+r;
}
int m = merge(nums,left,mid,right,temp);
return l+r+m;
}
return 0;
}
};