剑指offer35: 数组中的逆序对 java

题目:

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

思路:

        归并思想
        把数组分成前后两部分,逆序对数就等于前面的逆序对数 + 后面的逆序对数 + 前面和后面组合的逆序对数(一个前面的数一个后面的数)
        以7,5,6,4为例,分成两部分{7,5}和{6,4},{7,5}和{6,4}都是逆序对,count=2(逆序对数 + 后面的逆序对数);
        将{7,5}和{6,4}分别排序(避免重复)为{5,7}和{4,6},7大于6,则7大于6前的所有数,count=count+2=4;
        前面数组的指针向前移,指向5,5不大于6,后面数组的指针向前移,指向4,5大于4,是逆序对,count+1=5。
        copy就是用来排序的,两部分合并之后是排好序的,排好序放到array中对应的位置供后面使用,怎么排序呢,就是找逆序对的时候比较大小,将大的从后向前依次放,找完了逆序对,顺序也排好了。

代码:

public class Solution {
    public int InversePairs(int [] array) {
        if(array.length == 0){
            return 0;
        }
        int sum = count(array, 0, array.length-1);
        return sum;
    }
    private int count(int[] array, int start, int end){
        if(start == end){
            return 0;
        }
        int sum = 0;
        int mid = (start + end)/2;
        int left = count(array, start, mid);    //左边的逆序对数
        int right = count(array, mid+1, end);    //右边的逆序对数
        int count = 0;    //计数,左右结合出现的逆序对数(一个逆序对里面,一个是左边的,一个是右边的)
        int i = mid;    //遍历左边的
        int j = end;    //遍历右边的
        int[] copy = new int[end - start+1];    //辅助数组
        int index = end - start;
        while(i >= start && j >= mid+1){    //左右的数组有一个走完就结束
            if(array[i] > array[j]){    //如果i位置的数大于j位置的数,
                count += j - mid;    //则mid到j的所有数都比i小
                if(count > 1000000007){    //count大于1000000007时,count % 1000000007余数就不再是count了
                    count = count % 1000000007;
                }
                copy[index] = array[i];    //将大的数赋值给辅助数组
                index--;
                i--;
            }else{
                copy[index] = array[j];
                index--;
                j--;
            }
        }
        //把左或右边没走完的,直接赋值给辅助数组
        while(i >= start){
            copy[index] = array[i];
            i--;
            index--;
        }
        while(j >= mid + 1){
            copy[index] = array[j];
            j--;
            index--;
        }
        for(int r = 0; r <= end -start; r++){    //将排好序的数组放到array中对应的位置
            array[start+r] = copy[r];
        }
        sum = (count + left +right) % 1000000007;
        return sum;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值