力扣【排序】:315. 计算右侧小于当前元素的个数

  1. 题目描述:

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

  1. 算法思路:
  • 本题思路与LCR 170. 交易逆序对的总数思路类似,同样是通过利用归并排序计算某个元素右侧小于它的元素的个数
  • 本题难点在于:
    1. 归并排序会打乱数组次序,导致返回结果时我们已经不知道原来的次序如何,也就无法按照原来的次序排列计算结果
    2. 数组元素存在重复,因此没法使用unordered_map或map这类组件
  • 解决方法是建立一个下标数组,这个数组伴随着nums一同进行归并排序,只要同步处理元素和下标的排序,就可以手动维持一一对应的关系从而绕开两个难点
  • 剩下的计算和LCR 170. 交易逆序对的总数方式相近,由于我们计算的不再是子数组的逆序数个数而是某一个元素的右侧小于它的元素的个数,因此我们只能在nums[i] <= nums[j]时才更新计数,因为此时右侧子数组中所有小于nums[i]的元素都被遍历了,而在nums[i] > nums[j]时,我们应当累加这一计数,在合并时两个子数组都是有序的,所以左侧子数组大于nums[i]的元素对应的结果值一定是在nums[i]的基础上加几个数,并且如果右侧数组遍历完成,那么剩下的未遍历的左侧数组的元素的值都是最后累计的值,因此在j == right + 1时同样需要更新数据。而由于merge时结果数组中存放的结果分别只是左侧子数组和右侧子数组的,所以我们更新结果数组的值需要累加。
  1. 代码:

时间复杂度:与LCR 170分析方式类似,O(n log n)
空间复杂度:一共申请了下标数组,下标数组的辅助数组和nums的辅助数组一共三个辅助数组,递归带来的O(log n),所以最后应为O(n)

class Solution {
public:
    vector<int> countSmaller(vector<int>& nums) {
        int size = nums.size();
        tmp.resize(size, 0);
        index.resize(size, 0);
        index_tmp.resize(size, 0);
        for (int idx = 1; idx < size; ++idx) {
            index[idx] = idx;
        }

        vector<int> result(size, 0);

        MergeHelper(nums, 0, size - 1, result);
        return result;
    }

    void MergeHelper(vector<int> &nums, int left, int right, vector<int> &result) {
        if (left == right) {
            return;
        }
        int mid = left + (right - left) / 2;
        MergeHelper(nums, left, mid, result);
        MergeHelper(nums, mid + 1, right, result);
        Merge(nums, left, mid, right, result);
    }

    void Merge(vector<int> &nums, int left, int mid, int right, vector<int> &result) {
        for (int idx = left; idx <= right; ++idx) {
            tmp[idx] = nums[idx];
            index_tmp[idx] = index[idx];
        }

        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];
                index[k] = index_tmp[j];
                ++j;
            } else if (j == right + 1) {
                nums[k] = tmp[i];
                index[k] = index_tmp[i];
                result[index[k]] += count;
                ++i;
            } else if (tmp[i] > tmp[j]) {
                nums[k] = tmp[j];
                index[k] = index_tmp[j];
                ++count;
                ++j;
            } else if (tmp[i] <= tmp[j]) {
                nums[k] = tmp[i];
                index[k] = index_tmp[i];
                result[index[k]] += count;
                ++i;
            }
        }
    }

private:
    vector<int> tmp;
    vector<int> index;
    vector<int> index_tmp;
};
posted @ 2026-08-21 20:28  lf123z  阅读(3)  评论(0)    收藏  举报