剑指 Offer 51.数组中的逆序对

剑指 Offer 51.数组中的逆序对

在这里插入图片描述
不能用暴力解法!
归并排序
在这里插入图片描述
在分的过程中将数组拆分到只有一个元素,在治的过程中排序再合并,并且统计逆序对的数量。
在这里插入图片描述
与归并排序唯一的区别就是加了逆序对的计算,那么怎么计算逆序对呢?
当右边的A小于左边的B时,那么A会小于B右边到右边界所有的数,这些数的数量为mid-B的下标+1
将每一次归并时这些数量统计起来即为结果

class Solution {
    public int reversePairs(int[] nums) {
       if(nums.length <= 1) { //如果只有一个数直接返回0
           return 0;
       }
       int[] copy = new int[nums.length]; //不改变原数组,复制一份
       for(int i = 0; i < nums.length; i++) {
           copy[i] = nums[i];
       }
       int[] temp = new int[nums.length]; //用来存每一轮还没合并前的值,用来比较
       return reversePairs(copy, 0, nums.length - 1,temp);
    }
    public int reversePairs(int[] nums, int left, int right, int[] temp) {
        if(left == right) return 0; //拆分到只有一个数的时候返回0
        int mid = left + (right - left) / 2; //安全的求中点
        int leftPairs = reversePairs(nums, left, mid, temp); //记录左边的逆序对的数量并排序
        int rightPairs = reversePairs(nums, mid + 1, right, temp); //记录右边的逆序对的数量并排序
        if(nums[mid] <= nums[mid + 1]) return leftPairs + rightPairs; //如果左边最后一个数小于等于右边第一个数,就直接返回
        int crossPairs = mergeandCount(nums, left, right, mid, temp); //记录跨越左右两边的逆序对的数量
        return leftPairs + rightPairs + crossPairs;
    }
    public int mergeandCount(int[] nums, int left, int right, int mid, int[] temp) {
        for(int i = left; i <=right; i++) {
            temp[i] = nums[i];  //复制nums
        }
        int i = left; //左边第一个数
        int j = mid + 1; //右边第一个数
        int count = 0;
        for(int k = left; k <= right; k++) {
            if(i == mid + 1) {  //如果左边都搜索完了,就直接把右边的加上去
                nums[k] = temp[j];
                j++;
            }
            else if(j == right + 1) { //如果右边都搜索完了,就直接把左边的加上去
                nums[k] = temp[i];
                i++;
            }
            else if(temp[i] <= temp[j]) { //如果左边的数小于右边,就把左边的数添加进去
                nums[k] = temp[i];
                i++;
            }
            else { //如果右边的数小于左边,就把右边的数添加进去,说明右边的数大于左边剩下的所有的数,将左边剩下的数加起来
                nums[k] = temp[j];
                j++;
                count += mid - i + 1; 
            }
        }
        return count;
    }
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值