归并排序练习(二)—逆序对

题目
如果一个数组中,任何一个前面的数a,和任意一个后面的数b,如果(a,b)是降序的(a > b),就称为逆序对,返回数组中会有的逆序对。
举例:数组arr{3,1,2,4,0}
从3开始,a = 3 -> 此时的逆序对有(3,1),(3,2),(3.0)
a = 1,2时,有(1,0)(2,0)
a = 4 -> 此时的逆序对有 (4,0)
所以,数组中共有6个逆序对。

分析:
练习一中小和问题中,是按照找右侧比自己大的数的思路,merge时,左右组从头开始比较,如果左组 < 右组,则看右组中有多少数,进行累加。如果相等,则右组数字右移,来解决小和问题。
那么逆序对的思路也大致相同,数组分左右组并进行排序。

  1. 可以从尾向前遍历,左组 > 右组,则代表 左组当前数 >右组当前数至中点的所有数,所以逆序对共有右组当前位置 减去 中点位置的个数。且左组左移,如果相等或 左组 < 右组,则右组左移。
  2. 依然从头像尾遍历,如果 左组 > 右组,则代表 左组当前位置至中点的所有数 > 右组当前位置数,所以逆序对共有 中点位置 减去 左组当前位置个。 且右组右移,如果当前相等 或 左组 < 右组,则左组右移。

代码实现:
尾端查找

 public static int reverPairNumber(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }

        return process2(arr, 0, arr.length - 1);
    }

    public static int process2(int[] arr, int L, int R) {
        if (L == R) {
            return 0;
        }
        int M = L + ((R - L) >> 1);
        return process2(arr, L, M) +
                process2(arr, M + 1, R) +
                merge2(arr, L, M, R);

    }

    public static int merge2(int[] arr, int L, int M, int R) {
        int[] help = new int[R - L + 1];
        int p1 = M;
        int p2 = R;
        int ans = 0;
        int i = help.length - 1;

        while (p1 >= L && p2 >= M + 1) {

            ans += arr[p1] > arr[p2] ? p2 - M : 0;
            help[i--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--];
        }
        while (p1 >= L) {
            help[i--] = arr[p1--];
        }

        while (p2 >= M + 1) {
            help[i--] = arr[p2--];
        }

        for (int j = 0; j < help.length; j++) {
            help[j] = arr[j + L];
        }
        return ans;
    }

头部查找


    public static int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        return process(nums, 0, nums.length - 1);
    }

    public static int process(int[] nums, int L, int R) {
        if (L == R) {
            return 0;
        }
        int mid = L + ((R - L) >> 1);

        return process(nums, L, mid) + process(nums, mid + 1, R) + merge(nums, L, mid, R);
    }

    public static int merge(int[] nums, int L, int M, int R) {
        int[] help = new int[R - L + 1];
        int p1 = L;
        int p2 = M + 1;
        int ans = 0;
        int index = 0;
        while (p1 <= M && p2 <= R) {
            ans += nums[p1] > nums[p2] ? M - p1 +1 : 0;
            help[index++] = nums[p1] <= nums[p2] ? nums[p1++] : nums[p2++];
        }

        while (p1 <=M) {
            help[index++] = nums[p1++];
        }

        while (p2 <= R) {
            help[index++] = nums[p2++];
        }

        for (int j = 0; j < help.length; j++) {
            nums[L + j] = help[j];
        }
        return ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值