news 2026/4/16 14:19:50

【算法题】归并排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【算法题】归并排序

归并排序是基于分治思想的经典排序算法,核心逻辑是“拆分→排序→合并”:将数组递归拆分为子数组,分别排序后再合并为有序数组。它是稳定排序(相同元素相对位置不变),时间复杂度稳定为O(nlog⁡n)O(n\log n)O(nlogn),不仅能解决排序问题,更能高效处理“逆序对统计”“右侧元素计数”等衍生问题。本文通过4道经典题目,拆解归并排序在不同场景下的解题思路与代码实现。

一、排序数组

题目描述:
实现归并排序,将整数数组升序排列(不能使用内置排序函数,要求时间复杂度O(nlog⁡n)O(n\log n)O(nlogn))。

示例

  • 输入:nums = [5,2,3,1],输出:[1,2,3,5]

解题思路:
标准归并排序的三步流程:

  1. 拆分:将数组从中间拆分为左右两个子数组,递归排序子数组。
  2. 合并:用临时数组tmp合并两个有序子数组(双指针遍历左右子数组,取较小值存入临时数组)。
  3. 还原:将临时数组的有序元素写回原数组的对应区间。

完整代码:

classSolution{vector<int>tmp;public:vector<int>sortArray(vector<int>&nums){tmp.resize(nums.size());mergeSort(nums,0,nums.size()-1);returnnums;}voidmergeSort(vector<int>&nums,intleft,intright){if(left>=right)return;// 1. 取中间点intmid=(left+right)>>1;// 2. 分区间排序mergeSort(nums,left,mid);mergeSort(nums,mid+1,right);// 3. 合并intcur1=left,cur2=mid+1,i=0;while(cur1<=mid&&cur2<=right)tmp[i++]=nums[cur1]<=nums[cur2]?nums[cur1++]:nums[cur2++];while(cur1<=mid)tmp[i++]=nums[cur1++];while(cur2<=right)tmp[i++]=nums[cur2++];// 4. 还原for(inti=left;i<=right;i++){nums[i]=tmp[i-left];}}};

复杂度分析:

  • 时间复杂度:O(nlog⁡n)O(n\log n)O(nlogn),拆分的递归深度为O(log⁡n)O(\log n)O(logn),每层合并的时间为O(n)O(n)O(n)
  • 空间复杂度:O(n)O(n)O(n),临时数组tmp存储合并结果(递归栈深度为O(log⁡n)O(\log n)O(logn),可忽略)。

二、交易逆序对的总数(经典逆序对)

题目描述:
给定股票交易记录数组record,若前一天股价高于后一天股价,视为一个“交易逆序对”,返回逆序对总数。

示例

  • 输入:record = [9,7,5,4,6],输出:8(逆序对包括(9,7)(9,5)等)

解题思路:
在归并排序的合并阶段统计逆序对

  1. 拆分并递归排序左右子数组,同时统计子数组内部的逆序对。
  2. 合并时,若左子数组的当前元素nums[cur1] > nums[cur2],说明左子数组中cur1~mid的所有元素都与nums[cur2]构成逆序对,逆序对数量增加mid - cur1 + 1
  3. 合并完成后,将有序元素写回原数组。

完整代码:

classSolution{vector<int>tmp;public:intreversePairs(vector<int>&record){tmp.resize(record.size());returnmergeSort(record,0,record.size()-1);}intmergeSort(vector<int>&nums,intleft,intright){if(left>=right)return0;intret=0;// 1. 找中点划分区间intmid=(left+right)>>1;// 2. 找左/右区间个数并排序ret+=mergeSort(nums,left,mid);ret+=mergeSort(nums,mid+1,right);inti=0,cur1=left,cur2=mid+1;// 3. 一左一右找并合并排序while(cur1<=mid&&cur2<=right){if(nums[cur1]<=nums[cur2])tmp[i++]=nums[cur1++];else{ret+=mid-cur1+1;tmp[i++]=nums[cur2++];}}// 4. 处理剩余元素while(cur1<=mid)tmp[i++]=nums[cur1++];while(cur2<=right)tmp[i++]=nums[cur2++];// 5. 还原for(inti=left;i<=right;i++)nums[i]=tmp[i-left];returnret;}};

复杂度分析:

  • 时间复杂度:O(nlog⁡n)O(n\log n)O(nlogn),排序与统计逆序对的时间均为O(nlog⁡n)O(n\log n)O(nlogn)
  • 空间复杂度:O(n)O(n)O(n),临时数组tmp存储合并结果。

三、计算右侧小于当前元素的个数(带索引的逆序统计)

题目描述:
返回数组counts,其中counts[i]nums[i]右侧小于nums[i]的元素数量。

示例

  • 输入:nums = [5,2,6,1],输出:[2,1,1,0]

解题思路:
在归并排序中维护元素的原始索引,从而统计每个元素右侧更小的元素数量:

  1. index数组记录元素的原始索引,合并时同步维护索引的顺序。
  2. 合并阶段,若左子数组的当前元素nums[cur1] > nums[cur2],说明nums[cur1]右侧存在right - cur2 + 1个更小的元素,将该值累加到ret[index[cur1]]
  3. 合并完成后,同步还原numsindex数组的顺序。

完整代码:

classSolution{vector<int>ret;vector<int>index;inttmpNums[500010];inttmpIndex[500010];public:vector<int>countSmaller(vector<int>&nums){intn=nums.size();ret.resize(n);index.resize(n);for(inti=0;i<n;i++)index[i]=i;mergeSort(nums,0,n-1);returnret;}voidmergeSort(vector<int>&nums,intleft,intright){if(left>=right)return;intmid=(left+right)>>1;mergeSort(nums,left,mid);mergeSort(nums,mid+1,right);intcur1=left,cur2=mid+1,i=0;while(cur1<=mid&&cur2<=right){if(nums[cur1]<=nums[cur2]){tmpNums[i]=nums[cur2];tmpIndex[i++]=index[cur2++];}else{ret[index[cur1]]+=right-cur2+1;tmpNums[i]=nums[cur1];tmpIndex[i++]=index[cur1++];}}while(cur1<=mid){tmpNums[i]=nums[cur1];tmpIndex[i++]=index[cur1++];}while(cur2<=right){tmpNums[i]=nums[cur2];tmpIndex[i++]=index[cur2++];}for(inti=left;i<=right;i++){nums[i]=tmpNums[i-left];index[i]=tmpIndex[i-left];}}};

复杂度分析:

  • 时间复杂度:O(nlog⁡n)O(n\log n)O(nlogn),排序与统计的时间均为O(nlog⁡n)O(n\log n)O(nlogn)
  • 空间复杂度:O(n)O(n)O(n),存储临时数组和索引数组。

四、翻转对(扩展逆序对)

题目描述:
i < jnums[i] > 2 * nums[j],则称(i,j)为“翻转对”,返回数组中的翻转对总数。

示例

  • 输入:nums = [1,3,2,3,1],输出:2(翻转对为(3,1)(3,1)

解题思路:
在归并排序的合并前阶段统计翻转对

  1. 拆分并递归排序左右子数组,同时统计子数组内部的翻转对。
  2. 合并前,用双指针遍历左右子数组:若nums[cur1] > 2 * nums[cur2],则左子数组中cur1~mid的所有元素都与nums[cur2]构成翻转对,翻转对数量增加mid - cur1 + 1,并右移cur2;否则右移cur1
  3. 统计完成后,合并两个有序子数组并写回原数组。

完整代码:

classSolution{inttmp[50010];public:intreversePairs(vector<int>&nums){returnmergeSort(nums,0,nums.size()-1);}intmergeSort(vector<int>&nums,intleft,intright){if(left>=right)return0;intret=0;intmid=(left+right)>>1;ret+=mergeSort(nums,left,mid);ret+=mergeSort(nums,mid+1,right);// 合并前统计翻转对intcur1=left,cur2=mid+1;while(cur1<=mid){while(cur2<=right&&nums[cur1]/2.0<=nums[cur2])cur2++;if(cur2>right)break;ret+=right-cur2+1;cur1++;}// 合并两个有序子数组cur1=left,cur2=mid+1;inti=0;while(cur1<=mid&&cur2<=right)tmp[i++]=nums[cur1]<=nums[cur2]?nums[cur2++]:nums[cur1++];while(cur1<=mid)tmp[i++]=nums[cur1++];while(cur2<=right)tmp[i++]=nums[cur2++];for(inti=left;i<=right;i++)nums[i]=tmp[i-left];returnret;}};

复杂度分析:

  • 时间复杂度:O(nlog⁡n)O(n\log n)O(nlogn),统计翻转对与合并的时间均为O(nlog⁡n)O(n\log n)O(nlogn)
  • 空间复杂度:O(n)O(n)O(n),临时数组tmp存储合并结果。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 19:40:26

电商行业的数据分析工具推荐

电商行业的数据分析工具推荐 关键词:电商行业、数据分析工具、数据挖掘、可视化、数据洞察 摘要:本文聚焦于电商行业,深入探讨了适用于该领域的各类数据分析工具。从工具的背景介绍出发,阐述其目的、适用读者和文档结构,详细解释相关术语。接着介绍核心概念与联系,通过文…

作者头像 李华
网站建设 2026/4/3 6:02:51

Pulsar 特性在 AI 场景中的使用!

引言 没有意外&#xff0c;随着模型规模的持续增长和应用场景的日益复杂&#xff0c;AI Infra 也自然地从"单体架构" -> "分布式架构"进行演进&#xff0c;例如&#xff1a; 在大模型训练和推理阶段&#xff0c;随着模型规模的增长&#xff0c;需要通…

作者头像 李华
网站建设 2026/4/7 23:15:56

GRANT SELECT, DELETE ON 职工 TO USER1 WITH GRANT OPTION权限授予命令详解

一、语句结构分解 GRANT SELECT, DELETE ON 职工 TO USER1 WITH GRANT OPTION;各部分含义&#xff1a;部分含义GRANT授权命令关键字SELECT, DELETE授予的权限类型ON 职工权限作用的对象&#xff08;职工表&#xff09;TO USER1权限授予的用户WITH GRANT OPTION特殊权限选项 二、…

作者头像 李华
网站建设 2026/4/15 13:11:28

Linux网络编程-UDP 组播原理与实战

一、UDP 组播核心概念UDP 通信有三种典型模式&#xff0c;组播是单播和广播的中间形态&#xff0c;能精准向指定一组主机通信&#xff0c;大幅节省网络带宽&#xff1a;通信模式特点适用场景单播一对一&#xff08;两台主机端对端通信&#xff09;精准的点对点数据传输&#xf…

作者头像 李华
网站建设 2026/4/16 12:14:29

在外如何用手机像翻相册一样查看其他设备里所有文件?

在外急需调取家里NAS、电脑的资料&#xff1f;别再折腾U盘和复杂的远程设置了。今天就教你用节点小宝&#xff0c;像翻看自己手机相册一样&#xff0c;随时随地、直观地访问你所有设备里的文件。一把钥匙 打开所有设备的“文件抽屉”节点小宝的“远程文件”功能就是一把钥匙。它…

作者头像 李华
网站建设 2026/4/16 11:00:49

平价药店销售与管理系统

平价药店销售与管理系统一、系统概述随着信息技术的飞速发展&#xff0c;传统的药店管理方式已经不能满足现代化经营的需求。平价药店销售与管理系统旨在通过计算机技术为药店提供全面的信息化管理&#xff0c;涵盖药品信息管理、库存管理、销售管理、会员管理、收银结算等多项…

作者头像 李华