在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
题解:
1.一列数组
2.找出数组中的逆序对
3.逆序对是指数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对
4.注意时间上限的限制严格
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
解题思路:
对于没有严格时间限制的话,完全可以用两层循环解决
for( i=0; i<nums.length; i++ ){
for( j=i+1; j<nums.length; j++ ){
if( nums[j] < nums[i] ) sum++;
本题时间限制较为严格,虽然可以得到正确结果,但是数据量较大则超时
仔细分析元素比较过程可以发现,与二路归并排序合并为一路时元素比较过程是一样的,在运行时间上也有了保证。
class Solution {
public int reversePairs(int[] nums) {
if(nums==null||nums.length<1)
return 0;//空元素,1个元素没有逆序对
int[] copy=new int[nums.length];
System.arraycopy(nums,0,copy,0,copy.length);
return mergeSort(nums,copy,0,nums.length-1);}
public int mergeSort(int[] nums,int[] copy,int start,int end) {
if(start==end){//左右元素下标相等,说明区间内只有一个元素
copy[start]=nums[start];//记录下元素
return 0;}//没有逆序对,返回0
int middle=(start+end)/2;//找中间位置
int leftcount=mergeSort(copy,nums,start,middle);//左递归
int rightcount=mergeSort(copy,nums,middle+1,end);//右递归
int count=0;
int i=middle,j=end;
int lastindex=end;//区间一分为二,尾部元素开始向前移动,前后区间比较逆序对
while(i>=start&&j>=middle+1){//在此时递归区间内
if(nums[i]>nums[j]){//查找符合规则的逆序对
copy[lastindex--]=nums[i--];//记录下逆序对左值
count+=j-middle};//逆序对个数增加j-middle个
else//如果不满足逆序对条件
copy[lastindex--]=nums[j--];}//记录大数
while(i>=start)//i没有到头,剩有小元素
copy[lastindex--]=nums[i--];
while(j>=middle+1) //j没有走到中间,后半区间剩大元素
copy[lastindex--]=nums[j--];
return count+leftcount+rightcount;
}//一开始将整个数组元素一分为二,只比较了前半元素与后半元素可能的逆序对
}//在前/后半区间内也可能有逆序对,继续左右递归下去
Debug结果:
更多题解可前往公众号免费获取