剑指51-逆序对数【归并排序】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


题目

在这里插入图片描述
一道相当没有牌面的困难题。。。
第一时间想到动态规划,测了几个案例通过,心想:好嘛,爷困难题的一血要有了。
但是一提交,居然超时了。错误我都能理解,超时我确实无法理解,我第一次见到动态规划这个无往不利的都能超时,难道我的算法有问题?
估算了以下,大约(1 + 2 + 3 + … + (n - 1))= O(n^2),看了一下超时的数组,长度得有几千吧,难怪超时了。

二、归并排序法

看到题解中说要用归并排序,我迷茫了,为什么不用其他的排序,非要用归并呢?


归并的模板有点复杂,但是以前背过,大约分为三个函数来写,大概也知道要把计数放在哪里,开始。

归并排序的思路是:
递归地将子数组划分为左右两个部分,需要参数left,right,mid,辅助数组temp【存储递归过程中排序的结果】

  • 主方法:原测试方法;
  • “分”方法:递归算法,用于拆数组
  • “合并”方法:将左右两边合并到一个数组中。【合并方法使用左右对照双指针,而本计数的核心也在这里若存在一次左>右,将count += mid - left + 1【因为此时来了两边都已有序,右边的比左指针的右边都要小】】
 int count = 0;
    int temp[] = null;
    int[] nums = null;
    public int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) return 0;

        int len = nums.length;
        this.nums = nums;
        temp = new int[len];
        mergeSort(0, len - 1);
        return count;
    }

    public void mergeSort(int left, int right) {
        if (left >= right) return;
        int mid = (left + right) / 2;
        mergeSort(left, mid);
        mergeSort(mid + 1, right);
        merge(left, mid, right);
    }

    public void merge(int left, int mid, int right) {
        int lo = left;
        int hi = mid + 1;
        int index = left;
        while(lo <= mid && hi <= right) {
            if (nums[lo] > nums[hi]) {
                count += mid - lo + 1; //比归并排序多的地方,也是解题的关键
                temp[index++] = nums[hi++];
            } else{
                temp[index++] = nums[lo++];
            }
        }
        while(lo <= mid) temp[index++] = nums[lo++];
        while(hi <= right) temp[index++] = nums[hi++];

        for (int i = left; i <= right; i++) {
            nums[i] = temp[i];
        }

    }

public int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) return 0;

        int[] f = new int[nums.length];
        f[0] = 0;

        for (int i = 1; i < nums.length; i++) {
            int count = 0;
            for (int j = i - 1; j >= 0; j--) {
                if (nums[j] > nums[i]) count++;
                f[i] = f[i - 1] + count;
            }
        }
        return f[nums.length - 1];
    }

顺便贴一波之前的垃圾动态规划,我测了很大的数组也通过了,按理说应该没啥问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值