【刷题】计算右侧小于当前元素的个数-分治

 题目链接:. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=O83Ahttps://leetcode.cn/problems/count-of-smaller-numbers-after-self/

代码:

class Solution {
    int[] ret;  // 用于存储结果,每个元素右边比它小的元素个数
    int[] index;  // 记录元素在原始数组中的下标
    int[] indexTmp;  // 用于临时存储合并过程中的下标
    int[] tmp;  // 用于临时存储合并过程中的元素值

    public List<Integer> countSmaller(int[] nums) {
        int n = nums.length;
        ret = new int[n];  // 初始化结果数组
        index = new int[n];  // 初始化下标数组
        indexTmp = new int[n];  // 初始化临时下标数组
        tmp = new int[n];  // 初始化临时排序数组
        
        // 初始化 index 数组,记录每个元素的初始下标
        for (int i = 0; i < n; i++) {
            index[i] = i;
        }
        
        // 开始归并排序
        mergeSort(nums, 0, n - 1);
        
        // 将结果数组转化为 List 形式输出
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            result.add(ret[i]);
        }
        return result;
    }

    // 归并排序算法
    private void mergeSort(int[] nums, int left, int right) {
        if (left >= right) return;
        
        int mid = (left + right) / 2;
        // 分治,递归处理左半部分和右半部分
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        
        // 合并两个有序的子数组
        int cur1 = left, cur2 = mid + 1, i = 0;
        while (cur1 <= mid && cur2 <= right) {
            if (nums[cur1] <= nums[cur2]) {
                // 左边元素小于等于右边,不形成逆序对;大的元素放进tmp(降序归并)
                tmp[i] = nums[cur2];
                indexTmp[i++] = index[cur2++];
            } else {
                // 左边元素大于右边,形成逆序对
                ret[index[cur1]] += right - cur2 + 1;  // 更新逆序对的数量
                tmp[i] = nums[cur1];
                indexTmp[i++] = index[cur1++];
            }
        }
        
        // 合并剩余的元素
        while (cur1 <= mid) {
            tmp[i] = nums[cur1];
            indexTmp[i++] = index[cur1++];
        }
        while (cur2 <= right) {
            tmp[i] = nums[cur2];
            indexTmp[i++] = index[cur2++];
        }
        
        // 将合并后的结果写回原数组和下标数组
        for (int j = left; j <= right; j++) {
            nums[j] = tmp[j - left];
            index[j] = indexTmp[j - left];
        }
    }
}

注意:

index 数组在你的程序中用于记录原始数组中元素的下标,以便在排序的过程中能够跟踪每个元素在原数组中的位置。这是为了保证在归并排序过程中,逆序对统计时能够正确记录每个元素在原数组中的位置,而不是其当前排序后的位置。

具体作用

在归并排序过程中,我们会对数组 nums 进行分割并排序,但我们关心的不是排序后的新位置,而是元素在原数组中的位置。因此,通过维护 index 数组,归并时可以:

  1. 正确追踪元素的位置:在归并的过程中,元素的下标会发生变化,但我们需要知道这些元素在原数组中的下标来更新逆序对的统计。所以,index 数组帮助我们追踪每个元素的原始位置。

  2. 更新逆序对结果:当我们发现 nums[cur1] > nums[cur2] 时,意味着对于 nums[cur1] 这个位置的元素来说,存在 right - cur2 + 1 个逆序对。因此,我们通过 index[cur1] 得到 nums[cur1] 在原数组中的下标,然后更新 ret[index[cur1]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小小小关同学

你的支持就是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值