归并1.逆序对+小和问题(归并)

这篇博客介绍了如何使用归并排序算法有效地计算数组中的逆序对总数以及每个元素右边比它大的数的和(小和)。通过递归地将数组分为两部分并进行归并,在归并过程中计算逆序对和小和,同时对结果取模以防止溢出。这种方法在处理大规模数据时具有较高的效率。
摘要由CSDN通过智能技术生成

求一个数组的逆序对总数=求一个数右边有多少个数比它小

逆序对就是一个数组中前面的值和大于后面的值的一组数。
那么把数组分成前后两部分,分别进行归并,归并到最后merge两个数组,在这个过程中排序,并且计算出有多少个数是逆序的。
这样到后来归并两个数组的时候,已经知道两个数组各自有多少逆序对了,只需要计算归并过程中产生的逆序对。因为已经是排序完的,所以找到第一个大于第二段中的值的时候,第二个值一定小于全部的第一段中的值,所以count要加上第一段中的剩下的所有数据。
注意两点1.进行移位操作的时候一定记得加上括号,因为优先级较低。
2.进行计算的时候因为数据量比较大,所以都要取余

public class Solution {
    public int InversePairs(int [] array) {
        if(array==null || array.length==0){
            return 0;
        }
        int res=mergeSort(array,0,array.length-1);
        return res%1000000007;
    }
    public int mergeSort(int[] arr,int lo,int hi){
        if(lo==hi){
            return 0;
        }
        int mid=lo+((hi-lo)>>1);
        int res1=mergeSort(arr,lo,mid)%1000000007;
        int res2=mergeSort(arr,mid+1,hi)%1000000007;
        int res3=merge(arr,lo,mid,hi)%1000000007;
        return (res1+res2+res3)%1000000007;
    }
    public int merge(int[] arr,int lo,int mid,int hi){
        int[] res=new int[hi-lo+1];
        int cur=0;
        int cur1=lo;
        int cur2=mid+1;
        int count=0;
        while(cur1<=mid && cur2<=hi){
            if(arr[cur1]>arr[cur2]){
                count+=mid-cur1+1;
                count%=1000000007;
            }
            if(arr[cur1]<=arr[cur2]){
                res[cur++]=arr[cur1++];
            }else{
                res[cur++]=arr[cur2++];
            }
        }
        while(cur1<=mid){
            res[cur++]=arr[cur1++];
        }
         while(cur2<=hi){
             res[cur++]=arr[cur2++];
         }
        for(int i=0;i<res.length;i++){
            arr[lo+i]=res[i];
        }
        return count;
    }
}

求一个数组的小和=求一个数右边有多少个比它大

小和就是左边所有小于自己的和,返回一个所有数的小和之和,每次sort或者merge都产生一个小和,最终返回3个小和之和。在merge的过程中,找左边所有小于自己的数,其实就是找右边所有大于自己的数,也就是merge时右边的值直接排序并跳过,左边的值小的话就是右边此时的剩下的值都大于左边这个数,左边这个数乘右边数的数量就是左边这个数产生的小和。

  public static int smallSum(int[] a){//小和问题,就是求出一个数组的每个值的(左边所有小于它的值和)和
        //利用递归来解决,看成是求每个值右边有几个比它大的值
        if(a==null &&a.length<=2)return 0;
        return merge(a,0,a.length-1);
    }
    static int mergeSort(int[] a,int L,int R){
        if(L==R)return 0;
        int mid=L+((R-L)>>1);
        int r1=mergeSort(a,L,mid);
        int r2=mergeSort(a,mid+1,R);
        int r3=merge(a,L,mid,R);
        return r1+r2+r3;
    }
    static int merge(int[] a,int L,int mid ,int R){
        int[] help=new int[R-L+1];
        int p1=L;
        int p2=mid+1;
        int i=0;
        int rst=0;
        while(p1<=mid && p2<=R){
            rst+=a[p1]<a[p2]?(a[p1]*(R-p2+1)):0; //注意这里是减p2,加一才会算上另一个边界
            help[i++]=a[p1]<=a[p2]?a[p1++]:a[p2++];
        }
        while(p1<=mid){
            help[i++]=a[p1++];
        }
        while(p2<=R){
            help[i++]=a[p2++];
        }
        for(int j=0;j<help.length;j++){
            a[L+j]=help[j];
        }
        return rst;
    }
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值