【剑指offer刷题笔记】51.数组中的逆序对

本文介绍如何使用归并排序算法求解数组中的逆序对问题,通过调整合并过程中的比较逻辑,计数逆序对的数量。实例演示了代码实现和逆序对的打印,适合理解排序与逆序对计数的结合应用。

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

剑指No.51_数组中的逆序对

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

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

  • 基于归并排序实现的解法
    本文所实现的解法基于我之前写的关于归并排序中的代码归并排序,在聚合函数部分做了一些改动。详细的解释可以看剑指offer。
public class MySolution {
//    辅助数组
    private int[] aux;
//    返回结果
    private int result;
    public int reversePairsWay(int[] nums){
        aux = new int[nums.length];
        mergeSort(nums, 0, nums.length - 1);
        return result;
    }

    public void mergeSort(int[] nums, int low, int high){
        if (low >= high)
            return;
        int middle = low + (high - low) / 2;
        mergeSort(nums, low, middle);
        mergeSort(nums, middle + 1, high);
        merge(nums, low, middle, high);
    }
//  以上部分与归并排序完全相同


    public void merge(int[] nums, int low, int middle, int high){
//        这里由于要求指针从后往前移动,所以这样初始化左右子数组的指针
        int i = middle;
        int j = high;
//        给辅助数组赋值
        for (int k = low; k <= high; k++){
            aux[k] = nums[k];
        }

//        从数组的高位开始填入
        for (int k = high; k >= low; k--){
//            左数组添加完毕
            if (i < low)
                nums[k] = aux[j--];
//            右数组添加完毕
            else if (j < middle + 1)
                nums[k] = aux[i--];
//            左数组指针位置比右数组指针位置大
            else if (aux[i] > aux[j]) {
//                关键:左比右大,说明存在逆序对,而存在几个就是j - middle个,因为右子数组中在aux[j]左边的都小于等于它,
//                所以这些元素都和aux[i]构成逆序对
                result += (j - middle);
//                把更大的元素放在数组末尾
                nums[k] = aux[i--];
            }
            else
                nums[k] = aux[j--];
        }
    }
  • 更新代码,输出结果且打印出数组中的逆序对
/**
 * @Description:
 * 归并应用:逆序对问题,在一个数组中,如果左边的数字比右边的数字大,则这两个数字构成一个逆序对,请打印所有逆序对,求出总数
 * @Author: chong
 * @Data: 2021/6/20 2:27 下午
 */
public class reversePairs {
    int[] aux;
    int res;
    public int reversePairs(int[] nums) {
        aux = new int[nums.length];
        res = 0;
        reversePairs(nums, 0, nums.length - 1);
        return res;
    }

    public void reversePairs(int[] nums, int low, int high){
        if (low >= high)
            return;
        int mid = low + ((high - low) >> 1);
        reversePairs(nums, low, mid);
        reversePairs(nums, mid + 1, high);
        merge(nums, low, mid, high);
    }

    public void merge(int[] nums, int low, int mid, int high){
        int left = low;
        int right = mid + 1;
        for (int i = low; i <= high; i++){
            aux[i] = nums[i];
        }

        for (int i = low; i <= high; i++){
            if (left > mid)
                nums[i] = aux[right++];
            else if (right > high)
                nums[i] = aux[left++];
            else if (aux[left] > aux[right]){
                res += mid - left + 1;
                for (int k = left; k <= mid; k++)
                    System.out.println("逆序对:[" + aux[k] + ", " + aux[right] + "]");
                nums[i] = aux[right++];
            }else
                nums[i] = aux[left++];
        }
    }

    @Test
    public void test(){
        int[] nums = {7, 5, 6, 4};
        int res = reversePairs(nums);
        System.out.println(res);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值