java 剑指offer之[数据结构 中等]JZ51 数组中的逆序对

题目的链接在这里:https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5


题目大意

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007

数据范围: 对于 50%50% 的数据, size\leq 10^4size≤10
4

对于 100%100% 的数据, size\leq 10^5size≤10
5

数组中所有数字的值满足 0 \le val \le 10000000≤val≤1000000

要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)


一、示意图

在这里插入图片描述

二、解题思路

归并排序

归并排序

代码如下:

public class Solution {
 int count=0;
        int[]temp;
        public int InversePairs(int [] array) {
                //数组中的逆序对 前一个数字大于后一个 那就是一个逆序对 两个数组成一个逆序对
                temp=new int[array.length];
                mergeSort(array,0,array.length-1);
                return count;
        }

        private void mergeSort(int[] array, int left, int right) {
                if(left>=right)
                        return;
                int mid=(left+right)/2;
                //然后排其中两个序
                mergeSort(array,left,mid);
                mergeSort(array,mid+1,right);
                merge(array,left,mid,right);
        }
        //合并left mid mid+1 right 这两个有序数组的同时 计算逆序对
        private void merge(int[] array, int left, int mid, int right) {
                int i=left;
                int j=mid+1;
                int k=left;
                //当前面数组也就是i指针移动的时候 在j之前的都是比i小的元素
                //这里合并的思路就是 两边比大小 然后把小的赋值
                while (i<=mid&&j<=right){
                        //说明右边的更大一点
                        if(array[i]<=array[j]){
                                temp[k++]=array[i++];
                                //为什么是j-mid-1呢 当i比j要小的时候
                               // count=(count+(j-mid-1))%1000000007;

                        }
                        else {
                               //因为归并排序是从小到大的有序排序 所以一旦出现 i比j大的情况的话 就说明i比j之前的都要大
                                //mid前面又多少个j比当前的temp要小 可以这么理解 i向前移动了多少步 就说明
                                //合并的时候 left到mid 这个小的已经有序了 而mid+1 到right也已经有序了
                                   //换个思路来说 那也就是 i之后到mid的 都比当前的j要大 那就可以以当前j为终点 进行一波更新
                                count=(count+(mid-i+1))%1000000007;
                                temp[k++] = array[j++];
                        }
                }
                //前面总有一个会还没结束的
                while (i<=mid){
                        temp[k++]=array[i++];
                        //最关键的是这个统计的数量
                     //   count=(count+(right-mid))%1000000007;
                }
                while (j<=right){
                        temp[k++]=array[j++];
                }

                //然后把temp的值转入到array之中
                for(int index=left;index<=right;index++){
                        array[index]=temp[index];
                }
        }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值