跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

分治思想实战:归并排序与数组逆序对详解

归并排序采用分治策略,将数组二分至单元素后有序合并,时间复杂度 O(nlogn)。本文结合实例演示其 C++ 实现,并深入探讨如何扩展该算法以统计数组逆序对。核心在于合并阶段利用子数组有序特性,当右侧元素小于左侧当前元素时,左侧剩余部分均与其构成逆序关系,从而在排序过程中完成计数。

极光发布于 2026/3/30更新于 2026/10/2589 浏览
分治思想实战:归并排序与数组逆序对详解

47. 归并排序

题目链接

  • 215. 数组中的第 K 个最大元素 - LeetCode
  • 912. 排序数组 - LeetCode

题目描述

给定一个整数数组 nums,将其升序排列。

题目示例

文章配图 文章配图

解法:归并排序

算法思路

归并排序是「分而治之」思想的典型应用。整个过程可以拆解为两个核心步骤:

  1. 分(Divide):将数组不断二分,直到子数组长度为 1。此时每个元素自身有序,问题转化为「左半部分排序」+「右半部分排序」。
  2. 治(Conquer):合并两个已排序的子数组,生成一个更长的有序数组。重复此过程直至整个数组有序。

C++ 代码实现

class Solution {
public:
    vector<int> tmp; // 辅助数组,用于存放合并后的结果

    void mergesort(vector<int>& nums, int left, int right) {
        if (left == right) return;

        // 1. 选择中间点划分区间
        int mid = (right - left) / 2 + left;
        
        // 2. 递归排序左右区间
        mergesort(nums, left, mid);
        mergesort(nums, mid + 1, right);

        
         cur1 = left, cur2 = mid + , i = ;
         (cur1 <= mid && cur2 <= right) {
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
        }
        
         (cur1 <= mid) tmp[i++] = nums[cur1++];
         (cur2 <= right) tmp[i++] = nums[cur2++];

        
         ( i = left; i <= right; i++) {
            nums[i] = tmp[i - left];
        }
    }

    {
        tmp.(nums.());
        (nums, , nums.() - );
         nums;
    }
};
// 3. 合并两个有序数组
int
1
0
while
// 处理剩余元素
while
while
// 将临时数组还原回原数组对应位置
for
int
vector<int> sortArray(vector<int>& nums)
resize
size
mergesort
0
size
1
return

流程解析

文章配图


48. 数组中的逆序对

题目链接

  • LCR 170. 交易逆序对的总数 - LeetCode

题目描述

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

题目示例

文章配图 文章配图

解法:利用归并排序的过程——分治

算法思路

统计逆序对最经典的方法就是基于归并排序。我们不需要枚举所有数对,而是利用归并过程中「两个子数组均有序」的特性来快速计算。

为什么可以用归并排序? 将数组从中间划分为左右两部分,逆序对只可能产生于三种情况:

  1. 两个元素都在左半部分;
  2. 两个元素都在右半部分;
  3. 一个在左半部分,一个在右半部分。

前两种情况可以通过递归解决,第三种情况(跨区间逆序对)正是归并排序合并阶段需要处理的。当我们在合并两个有序数组时,如果发现右侧当前元素小于左侧当前元素,那么左侧剩余的所有元素都大于该右侧元素,它们都能与该右侧元素构成逆序对。

如何高效统计? 在合并过程中维护一个计数器。假设当前正在比较 nums[cur1] 和 nums[cur2]:

  • 若 nums[cur1] <= nums[cur2]:左侧元素较小,不构成逆序,放入临时数组。
  • 若 nums[cur1] > nums[cur2]:发现逆序。由于左侧数组已排序,[cur1, mid] 范围内的所有元素都大于 nums[cur2]。因此,逆序对数量增加 mid - cur1 + 1。

C++ 代码实现

class Solution {
public:
    int count = 0;
    vector<int> tmp;

    int reversePairs(vector<int>& record) {
        tmp.resize(record.size());
        mergesort(record, 0, record.size() - 1);
        return count;
    }

    void mergesort(vector<int>& nums, int left, int right) {
        if (left >= right) return;

        int mid = (right - left) / 2 + left;
        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[i++] = nums[cur1++];
            } else {
                // 关键逻辑:左侧剩余元素均大于右侧当前元素
                count += mid - cur1 + 1;
                tmp[i++] = nums[cur2++];
            }
        }

        while (cur1 <= mid) tmp[i++] = nums[cur1++];
        while (cur2 <= right) tmp[i++] = nums[cur2++];

        for (int i = left; i <= right; i++) {
            nums[i] = tmp[i - left];
        }
    }
};

流程解析

文章配图 文章配图 文章配图

通过上述分析,我们可以看出归并排序不仅是一个排序工具,其合并过程的单调性特性使其成为解决逆序对问题的利器。时间复杂度稳定在 O(nlogn),空间复杂度为 O(n)。

目录

  1. 47. 归并排序
  2. 题目链接
  3. 题目描述
  4. 题目示例
  5. 解法:归并排序
  6. 算法思路
  7. C++ 代码实现
  8. 流程解析
  9. 48. 数组中的逆序对
  10. 题目链接
  11. 题目描述
  12. 题目示例
  13. 解法:利用归并排序的过程——分治
  14. 算法思路
  15. C++ 代码实现
  16. 流程解析

更多推荐文章

查看全部
  • 本地运行 LLM 的 AI 助手 Jan 部署与使用指南
  • Stable Diffusion WebUI 文件夹结构与模型使用指南
  • VS Code 远程连接服务器后 GitHub Copilot 无法使用修复方案
  • HarmonyOS 5.0 物联网开发:基于星闪的智能家居边缘计算网关
  • Apache IoTDB 部署全指南:AINode 独立部署与 Kubernetes 集群部署
  • C++ 实现 B2115 密码翻译解密算法
  • 大模型开发基本功:模型转换与推理加速实践
  • 如何用PDF Arranger轻松管理PDF文件:完整操作指南
  • RAG 技术演进:DeepSeek 与 Neo4j 构建 GraphRAG 企业智能体系
  • AIGC Bar API 站接入与工程化最佳实践
  • C++ STL:从零手写 String 类及高频易错点复盘
  • MySQL 与 PostgreSQL 核心差异深度对比
  • Python 的十大核心特性详解
  • 网络编程核心:路由表、MTU/MSS、ARP、NAT 及代理技术解析
  • C++ 实现非中心 t 分布的 PDF 与 CDF 计算(含源码)
  • 利用 AI 大模型一键生成高清短视频的开源项目介绍
  • AI-Render:把 Stable Diffusion 接进 Blender 的折腾实录
  • Python 爬虫实战:跨境电商数据采集与代理 IP 策略
  • 飞书机器人与Claude Code交互:从手机指令到AI处理的全自动流程
  • node-llama-cpp 常见错误处理与调试方法

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online