剑指offer-test35

35.数组中的逆序对(涉及归并排序)
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

第一就是暴力求解法,时间复杂度为o(n^2),空间复杂度o(1)

第二种思路就是使用归并排序的思想进行处理,时间复杂度o(nlog(n)),空间复杂度0(n)*/
可以参考以下这位作者对归并排序的讲解,来理解归并排序。更容易:https://blog.csdn.net/k_koris/article/details/80508543

思路
1.先用两个指针分别指向两个子数组的末尾,并每次比较两个指针指向的数字。
2.如果第一个子数组中的数字大于第二个数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数。
3.如果第一个数组的数字小于或等于第二个数组中的数字,则不构成逆序对。每一次比较的时候,我们都把较大的数字从后面往前复制到一个辅助数组中,确保 辅助数组(记为copy) 中的数字是递增排序的。在把较大的数字复制到辅助数组之后,把对应的指针向前移动一位,接下来进行下一轮比较。

public class Solution {
    int count=0;
    public int InversePairs(int [] array) {
        if(array.length<=0||array==null){
            return 0;
        }
        //初始化该数组,该数组作为存放临时排序的结果,最后要将排序的结果复制到原数组中
        int[] copy=new int[array.length];
        for(int i=0;i<array.length;i++){
            copy[i]=array[i];
        }
        int  Num=divideMerge(array,copy,0,array.length-1);
        //delete[] copy;//删除临时数组
        return Num;
    }
    private int divideMerge(int[] arr,int[] copy,int start,int end){
        //递归的终止条件
        if(start==end){
            copy[start]=arr[start];
            return 0;
        }
        //计算中间值,注意溢出
        int mid=(end+start)/2;
        //先递归分别计算左右部分逆序对
        int leftNum=divideMerge(arr,copy,start,mid)%1000000007;
        int rightNum=divideMerge(arr,copy,mid+1,end)%1000000007;
        
        //逆序对计算
        int i=mid;          //last_in_left
        int j=end;        //last_in_right
        int index=end;// 辅助数组的下标
        int count=0;
        //再统计出两个相邻子数组之间的逆序对的数目
        while((start<=i)&& (mid+1<=j)){
            if(arr[i]>arr[j]){
                count+=j-mid;//如果左边的最后一个小于右边的最后一个,那么
                count%=1000000007;
                copy[index--]=arr[i--];//把大的存进去并放在辅助数组的最后一个,并且移动大数数所在的数组的指针既可。保证辅助素组中的数字是递增排序的。
            }else{
                 //若前面小于后面,那么将大的数存进去,并且移动大数数所在的数组的指针既可
                copy[index--]=arr[j--];
            }
        }
        //添加剩下的前半部分到拷贝数组中
        for(;i>=start;i--)
            copy[index--]=arr[i];
        //while(start<=i)
          //  copy[index--]=arr[i--];
         //添加剩下的后半部分到拷贝数组中
        for(;j>=mid+1;j--)
            copy[index--]=arr[j];
        //while(mid+1<=j)
          //  copy[index--]=arr[j--];
        //将排好序的copy数组复制到arr中
       for(int k=start;k<=end;k++)
          arr[k]=copy[k];
        //int k=0;
        //while(start<=end)
           // arr[start++]=copy[k++];
        return (count+leftNum+rightNum)%1000000007;
     }
}

1.先把数组分割成子数组
2.在统计出子数组内部的逆序对的数目
3.然后统计出相邻子数组之间的逆序对数目
4.在统计逆序对的过程中,需要对数组进行排序,因此增加了一个辅助数组。
5.最后将排好序的数组返回给arr数组。即合并数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值