【C++算法】49.分治_归并_计算右侧小于当前元素的个数

文章目录


题目链接:

315. 计算右侧小于当前元素的个数


题目描述:


解法

归并排序(分治)

当前元素的后面,有多少个比我小。(降序)


C++ 算法代码:

cpp 复制代码
class Solution 
{
    vector<int> ret;        // 存储结果:每个元素右侧小于当前元素的个数
    vector<int> index;      // 记录 nums 中当前元素的原始下标,用于追踪元素位置
    int tmpNums[500010];    // 临时数组,用于归并排序中合并两个子数组
    int tmpIndex[500010];   // 临时数组,用于保存合并后的索引顺序
public:
    vector<int> countSmaller(vector<int>& nums) 
    {
        int n = nums.size();
        ret.resize(n);      // 初始化结果数组大小,默认值都是0
        index.resize(n);    // 初始化索引数组大小
        
        // 初始化索引数组,记录每个元素的原始位置
        for(int i = 0; i < n; i++)
            index[i] = i;
            
        mergeSort(nums, 0, n - 1);  // 对整个数组进行归并排序
        return ret;  // 返回结果数组
    }

    void mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return;  // 基本情况:如果区间只有一个元素或为空,则直接返回
        
        // 1. 根据中间元素,划分区间
        int mid = (left + right) >> 1;  // 计算中间位置,相当于 (left + right) / 2
        
        // 2. 递归地处理左右两部分
        mergeSort(nums, left, mid);       // 排序左半部分
        mergeSort(nums, mid + 1, right);  // 排序右半部分
        
        // 3. 合并两个有序子数组,同时计算右侧小于当前元素的个数
        int cur1 = left, cur2 = mid + 1, i = 0;  // cur1指向左子数组,cur2指向右子数组,i遍历辅助数组
        
        while(cur1 <= mid && cur2 <= right)  // 当两个子数组都还有元素时
        {
            if(nums[cur1] <= nums[cur2])  // 如果左子数组当前元素小于等于右子数组当前元素
            {
                tmpNums[i] = nums[cur2];       // 将右子数组的元素放入临时数组
                tmpIndex[i++] = index[cur2++]; // 同时记录对应的原始索引
            }
            else  // 如果左子数组当前元素大于右子数组当前元素
            {
                // 核心逻辑:此时右子数组中从cur2到right的所有元素都小于当前的nums[cur1]
                ret[index[cur1]] += right - cur2 + 1;  // 将这些元素的数量累加到结果中
                
                tmpNums[i] = nums[cur1];       // 将左子数组的元素放入临时数组
                tmpIndex[i++] = index[cur1++]; // 同时记录对应的原始索引
            }
        }
        
        // 4. 处理剩余元素
        while(cur1 <= mid)  // 处理左子数组中剩余的元素
        {
            tmpNums[i] = nums[cur1];
            tmpIndex[i++] = index[cur1++];
        }
        
        while(cur2 <= right)  // 处理右子数组中剩余的元素
        {
            tmpNums[i] = nums[cur2];
            tmpIndex[i++] = index[cur2++];
        }
        
        // 5. 将临时数组中的元素复制回原数组
        for(int j = left; j <= right; j++)
        {
            nums[j] = tmpNums[j - left];    // 更新原数组中的元素值
            index[j] = tmpIndex[j - left];  // 更新原数组中元素对应的原始索引
        }
    }
};

图解

例如:nums = [5, 2, 6, 1]

  1. 初始化:

    • ret = [0, 0, 0, 0] (结果数组,初始全为0)

    • index = [0, 1, 2, 3] (原始索引数组)

  2. 第一次划分:

    • 将 [5, 2, 6, 1] 分为 [5, 2] 和 [6, 1]
  3. 处理左半部分 [5, 2]:

    • 进一步划分为 [5] 和 [2]

    • 这些是单个元素,不再划分

    • 合并 [5] 和 [2] (降序合并):

      • 比较 5 和 2,5 > 2,nums[cur1] > nums[cur2]
      • ret[index[cur1]] += right - cur2 + 1;
      • 因为左边元素大,所以选择左边元素,ret 不变
      • 合并后,左半部分变为 [5, 2],索引变为 [0, 1]
  4. 处理右半部分 [6, 1]:

    • 进一步划分为 [6] 和 [1]

    • 这些是单个元素,不再划分

    • 合并 [6] 和 [1] (降序合并):

      • 比较 6 和 1,6 > 1
      • 因为左边元素大,所以选择左边元素,ret 不变
      • 合并后,右半部分变为 [6, 1],索引变为 [2, 3]
  5. 最后合并[5, 2] 和 [6, 1] (降序合并):

    • 比较 5 和 6: 5 <= 6,选择右侧元素6,ret 不变
    • 比较 5 和 1: 5 > 1,这时右子数组中只有1比5小,所以ret[index[cur1]] += right - cur2 + 1 → ret[0] += 3 - 3 + 1 → ret[0] = 1
    • 比较 2 和 1: 2 > 1,右子数组中只有1比2小,所以 ret[index[cur1]] += right - cur2 + 1 →ret[1] += 3 - 3 + 1 → ret[1] = 1
  6. 最终结果:

    • ret = [2, 1, 1, 0]

3.第一次循环:while(cur1 <= mid && cur2 <= right)

4.第二次循环:while(cur1 <= mid && cur2 <= right)

5.第三次循环:while(cur1 <= mid && cur2 <= right)

6.处理剩余元素while(cur2 <= right)

相关推荐
扶尔魔ocy10 分钟前
【QT入门到晋级】用开源的自定义控件开发
c++·qt·自定义控件
AiNightVision11 分钟前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件
牧羊人.3331 小时前
卷积神经网络之VGG
人工智能·深度学习·神经网络·算法·cnn
akinggw1 小时前
libsherpacore - 基于 sherpa-onnx 的 C++ 语音交互静态库
c++·交互·语音识别
xiaoye-duck2 小时前
《C++ 项目:手写大模型接入 SDK》ChatGPT接口设计(中):全量响应实现和测试
网络·c++·语言模型·chatgpt
小郎君6582 小时前
Vue 多标签页的加载态设计:为什么我没有用 Suspense 实现 PageLoading
vue.js·算法
JJJennie7772 小时前
MAI Gateway私有化部署全攻略:大模型网关如何接入?附架构图
算法·gateway·ai网关·魔芋ai
東隅已逝,桑榆非晚2 小时前
算法3.双指针法-快乐数
c++·笔记·学习·算法
专注仿真2 小时前
卷积神经网络(CNN)算法详解
人工智能·python·算法·代码·大模型训练
FII工业富联科技服务2 小时前
多智能体如何进入制造现场?从业务协同到数字孪生验证
大数据·人工智能·算法·机器人·制造·数字孪生