//在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
//暴力方法超时,考虑归并排序
class Solution { public int reversePairs(int[] nums) { if(nums==null||nums.length<2){ return 0; } int len=nums.length; int []copy=new int[len]; //通常输入不许改变,复制一份 for(int i=0;i<len;i++){ copy[i]=nums[i]; } //辅助数组 int []temp=new int[len]; //归并排序 return reversPairs(copy,0,len-1,temp); } public int reversPairs(int []nums,int left,int right,int []temp){ if(left==right){ return 0; } int mid=(left+right)/2; //左边逆序数 int leftcount=reversPairs(nums,left,mid,temp); //右边逆序数 int rightcount=reversPairs(nums,mid+1,right,temp); //如果左边最后一个小于等于右边第一个,因为左右都排序了,所以左边全体小于右边,没有跨区间逆序数,直接返回两边的逆序数 if(nums[mid]<=nums[mid+1]){ return leftcount+rightcount; } //计算合并产生逆序数 int mergeCount=merge(nums,left,mid,right,temp); //返回两边+合并逆序数 return mergeCount+leftcount+rightcount; } public int merge(int []nums,int left,int mid,int right,int []temp){ for(int i=left;i<=right;i++){ temp[i]=nums[i]; } //i指针指向左半边起始 int i=left; //j指针指向右半边起始 int j=mid+1; int count=0; for(int k=left;k<=right;k++){ //左半边遍历完毕,把右半边剩下的放入 if(i==mid+1){ nums[k]=temp[j]; j++; }else if(j==right+1){ //右半边遍历完毕,把左半边剩下的放入 nums[k]=temp[i]; i++; }else if(temp[i]<=temp[j]){ //左边指针位置小于右边,不产生逆序数,直接把指针位置放回数组,指针向前移动 nums[k]=temp[i]; i++; }else{ //右半边指针位置较小,因为经过排序,那么左半边从i到末尾的mid的数全大于j位置的数,j位置逆序数为mid-i+1 //也就是i到mid全部数字个数 nums[k]=temp[j]; j++; count=count+(mid-i+1); } } return count; } }