归并排序

数组中的逆序对_牛客网

https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5?tpId=13&tqId=11188&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

归并排序使用分治策略,序列一分为二(O(1))后,将子序列递归排序(2 * T(n / 2)),最后合并有序子序列(O(n)),T(n) = 2 * T(n / 2) + O(n) = O(n * logn)。

一、归并排序

1、归并排序的实现

写递归函数就像开车,先系上安全带即先写出递归基。

public static void mergeSortCore(int[] arr, int lo, int hi) {
        if (lo == hi) { // <----- 安全带
            return;
        }
        int mid = ((hi - lo) >> 1) + lo;
        mergeSortCore(arr, lo, mid);
        mergeSortCore(arr, mid + 1, hi);
        merge(arr, lo, mid, hi);
    }

2、二路归并的实现

将两个有序序列合并为一个有序序列,如下(还有一个结构紧凑的写法,效率不高(merge2))

public static void merge(int[] arr, int lo,int mid, int hi) {
        int[] temp = new int[hi - lo + 1];
        int i = 0, p1 = lo, p2 = mid + 1;
        while (p1 <= mid && p2 <= hi) {
            temp[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid) {
            temp[i++] = arr[p1++];
        }
        while (p2 <= hi) {
            temp[i++] = arr[p2++];
        }
        for (i = 0; i < temp.length; i++) {
            arr[lo + i] = temp[i];
        }
    }

3、源码

二、剑指offer[51]

数组中的逆序对 题解

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

二路归并即merge,是将两个有序的序列合并为一个有序的序列,在两个子序列left、right合并过程中,当left中当前元素A小于right中当前元素B时,因为right序列已经有序,所以不用比较,A一定是left、right两个子序列当前剩余元素中最小的元素,这省去了A与B后其他元素比较的操作。

对于本题,在两个子序列left、right合并过程中,当left中当前元素A大于right中当前元素B时,因为right序列已经有序,所以不用比较,A一定大于right序列当前所有剩余元素,其全部可以与A组成逆序对,即通过一次比较可到一批逆序对,加速统计过程。

private int merge(int[] arr, int lo, int mid, int hi) {
    int[] temp = new int[hi - lo + 1];
    int index = 0;
    int count = 0;
    int p1 = lo, p2 = mid + 1;
    while (p1 <= mid && p2 <= hi) {
        // 与归并排序不同的地方,在merge过程中统计逆序对数
        if (arr[p1] > arr[p2]) {
            count += mid - p1 + 1;
            temp[index++] = arr[p2++];
        } else {
            temp[index++] = arr[p1++];
        }
    }
    while (p1 <= mid) {
        temp[index++] = arr[p1++];
    }
    while (p2 <= hi) {
        temp[index++] = arr[p2++];
    }
    for (int i = 0; i < temp.length; i++) {
        arr[lo++] = temp[i];
    }

    return count;

三、相关

小和问题

全部评论
"当left中当前元素A大于right中当前元素B时,因为right序列已经有序,所以不用比较,A一定大于right序列当前所有剩余元素,其全部可以与A组成逆序对" 你这个解释不太对,你可以尝试一下排序8,4,5,7,1,3,6,2,最后两个归并的数组是【4,5,7,8】和【1,2,3,6】,left中的4的确是大于right中的1,但并不代表4一定大于right中的每一个数字,应该是left中的剩余数组全部大于right中的1,因为left是已经按照从小到大排序过的
14 回复
分享
发布于 2020-03-24 12:55
应该是left中A的后面直到mid都与该元素构成逆序对
4 回复
分享
发布于 2020-04-13 10:40
滴滴
校招火热招聘中
官网直投
为什么我的只过了50%,粘贴了这两个函数,将局部变量count改为全局变量,为啥每ac呢???
点赞 回复
分享
发布于 2020-03-23 11:45
感谢,看你的代码看懂了,谢谢
点赞 回复
分享
发布于 2020-07-27 19:56
介绍得很清晰!爆赞
点赞 回复
分享
发布于 2021-04-19 06:40

相关推荐

39 4 评论
分享
牛客网
牛客企业服务