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

该博客介绍了一种使用归并排序算法解决数组中逆序对计数问题的方法。通过复制数组,避免原始数据改变,然后递归地进行拆分和合并操作,在合并过程中计算逆序对。在每次合并时,根据元素大小关系更新逆序对计数。最后返回总逆序对数。这种方法的时间复杂度低于暴力破解的O(n^2),实现了更高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、题目

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]
输出: 5

限制:

0 <= 数组长度 <= 50000

 

2、解题思路

(1)解决思路一:暴力破解(双循环,临时变量来存储逆序对的个数),时间复杂度o(n)

(2)解决思路二:归并排序;

​ (1)复制出来一个数组;(因为后续会对参数数组进行排序)

​ (2) 对数组拆分,拆分,再拆分;一直拆分到每组两个元素

​ (3)计算每组里面多少个逆序对

​ (4)合并相邻的两个分组(合并的时候进行计算 左边分组逆序对,右边分组逆序对,合并后逆序对)

​ (5)累加所有的逆序对个数即为整个数组的逆序对个数;

 

3、java代码
class Solution {
    public int reversePairs(int[] nums) {
    if (nums == null || nums.length < 2) {
            return 0;
        }

        // 为了不改变原数组,这里先将原数组拷贝一份
        int[] copy = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            copy[i] = nums[i];
        }
        //tmp用来存储排序后的数组
        int[] tmp=new int[nums.length];
        return reversePairs(nums,0,nums.length-1,tmp);
    }

   //拆分->拆分->合并->合并
    public int reversePairs(int[] nums, int left, int right, int[] tmp) {
        if (left >= right) {
            return 0;
        }
        //1、求出来中间值
        int mid = (left + right) / 2;
        //2、持续调用拆分合并的过程;先拆左边,再拆右边,然后再合并
        int leftvalue = reversePairs(nums, left, mid, tmp);
        int rightvalue = reversePairs(nums, mid+1, right, tmp);
        int mergevalue = this.merge_Array(nums, left, mid, right, tmp);
        return leftvalue + rightvalue + mergevalue;
    }

    //合并的方法
    private int merge_Array(int[] nums, int left, int mid, int right, int[] tmp) {
        for (int i = left; i <= right; i++) {
            tmp[i] = nums[i];
        }
        //定位两个指针来遍历需要合并的两个数据区间;tmp作为排序后的数组,nums作为排序前作为对照
        int i = left;
        int j = mid + 1;
        int count = 0;
        for (int k = left; k <= right; k++) {  //遍历整个数据区间
            if (i == mid + 1) {   //左边到头了,填充右边的元素
                nums[k]=tmp[j++];
            } else if (j == right + 1) {    //右边到头了,填充左边的元素
                nums[k]=tmp[i++];
            } else if(tmp[i]<=tmp[j]){    //左边的小于等于右边,则放左边的
                nums[k]=tmp[i++];
            } else{                         //右边的小于左边,则放右边的
                nums[k]=tmp[j++];
                count+=mid+1-i;
            }
            }
        return count;
            //返回逆序对
        }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值