【算法题】归并排序

归并排序是基于分治思想的经典排序算法,核心逻辑是“拆分→排序→合并”:将数组递归拆分为子数组,分别排序后再合并为有序数组。它是稳定排序(相同元素相对位置不变),时间复杂度稳定为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存储合并结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1155811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python数学可视化——显函数、隐函数及复杂曲线的交互式绘图技术

Python数学可视化技术概述Python提供了多种库用于数学可视化&#xff0c;包括显函数、隐函数及复杂曲线的交互式绘图。常用工具包括Matplotlib、SymPy、Plotly和Mayavi&#xff0c;适用于2D/3D图形、符号计算及动态交互。显函数绘图显函数&#xff08;如$y f(x)$&#xff09;可…

谢菲尔德大学:AI模型如何在陌生环境中保持“人性化“表现

当我们人类从一个熟悉的环境转移到完全陌生的地方时&#xff0c;往往需要重新适应当地的规则和习惯。比如一个在北京生活多年的人突然搬到成都&#xff0c;虽然同样是说中文&#xff0c;但在表达方式、社交礼仪&#xff0c;甚至是点菜习惯上都需要重新学习和调整。有趣的是&…

Java锁机制八股文

一、简短结论 CAS是基础&#xff1a;所有Java锁机制的底层都依赖CAS实现原子操作AQS是框架&#xff1a;ReentrantLock等JUC锁基于AQS&#xff0c;AQS使用CASCLH队列synchronized是混合锁&#xff1a;经历了偏向锁→轻量级锁→重量级锁的升级过程&#xff0c;内部大量使用CAS锁选…

【2026视频播放器】电脑手视频播放器 PotPlayer‌,KMPlayer,VLC media player,MPV,MPC-HC,GOM Player‌,ACG

视频播放器是我们日常观影、学习、工作的重要工具。本文将为大家推荐10款专业实用的PC端视频播放器&#xff0c;全部纯净无广 &#xff0c;支持超高清解码&#xff0c;满足不同用户的需求。 【地址】&#xff1a;https://tool.nineya.com/s/1iuc1h093 【资源也准备好了】&…

国内首例 AI 伴侣聊天提供者涉黄获刑,二审将开庭;OpenAI :大模型能力过剩,未来重心将转向系统层与应用层丨日报

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度的观点」、「…

微信视频号下载器,蝴蝶号视频下载

自媒体必备神器-微信视频号下载器 - 教你如何下载视频号视频 体积小、使用简单、支持 macOS 和 Windows 系统。 一、下载器简介 对于自媒体人来说&#xff0c;获取和保存微信视频号上的优质视频内容&#xff0c;是日常创作和学习的重要一环。为了帮助大家轻松下载微信视频号…

强烈安利9个AI论文平台,本科生毕业论文轻松搞定!

强烈安利9个AI论文平台&#xff0c;本科生毕业论文轻松搞定&#xff01; AI 工具让论文写作变得轻松高效 在当今这个信息爆炸的时代&#xff0c;本科生的毕业论文写作早已不再是单纯的学术挑战&#xff0c;而是一场与时间、效率和质量的较量。尤其是面对复杂的选题、繁重的文献…

全网最全研究生必用AI论文工具TOP8测评

全网最全研究生必用AI论文工具TOP8测评 2026年研究生必备AI论文工具测评&#xff1a;为何要关注这些工具&#xff1f; 随着人工智能技术的不断进步&#xff0c;越来越多的学术工作者开始依赖AI工具来提升论文写作效率与质量。对于研究生群体而言&#xff0c;从选题、文献综述到…

业务即代码:当DDD穿越古代商帮-第2集:第一次事件风暴

笔言: 在《1999点科技树》第九、十合集&#xff08;看见与守护&#xff1a;分布式系统的观测体系与安全架构&#xff09;中&#xff0c;我曾提及一个写作计划——将 DDD&#xff08;领域驱动设计&#xff09; 与 BIZBOK&#xff08;业务知识体系&#xff09; 深度融合&#xff…

别再纠结了:Lambda 还是 Kappa?流批统一这件事,真没你想得那么玄乎

“别再纠结了&#xff1a;Lambda 还是 Kappa&#xff1f;流批统一这件事&#xff0c;真没你想得那么玄乎”很多人一聊到流-批统一架构&#xff0c;第一反应就是一句话&#xff1a;“Lambda 太复杂&#xff0c;Kappa 才是未来。”听起来很有道理&#xff0c;对吧&#xff1f; 但…

10341_基于Springboot的珠宝销售网站

1、项目包含项目源码、项目文档、数据库脚本、软件工具等资料&#xff1b;带你从零开始部署运行本套系统。2、项目介绍随着科学技术和信息通讯的飞速发展&#xff0c;Internet极大的丰富和改变着我们生活的各个行业。随着Internet的普及应用&#xff0c;人们可以跨越时间和空间…

Linux在毕业设计中的核心难点与重点梳理(附避坑指南)

在计算机相关专业毕业设计中&#xff0c;Linux 常作为底层环境、服务器载体或核心操作平台&#xff0c;无论是嵌入式、后端开发、运维方向&#xff0c;都绕不开相关应用。但多数同学实操经验不足&#xff0c;容易在核心环节卡壳&#xff0c;本文梳理关键难点与重点&#xff0c;…

亲测好用8个一键生成论文工具,MBA论文写作必备!

亲测好用8个一键生成论文工具&#xff0c;MBA论文写作必备&#xff01; AI 工具如何成为论文写作的得力助手 在当今快节奏的学术环境中&#xff0c;MBA 学生和研究者常常面临时间紧、任务重的压力。尤其是在撰写论文时&#xff0c;从选题到成稿&#xff0c;每一个环节都需要大量…

智能电梯门禁(可视对讲联动梯控)方案实现梯控联动召梯、呼梯、访客联动功能,完全融入楼宇可视对讲门禁系统,核心通过协议对接 + 物理接线双重方式,保障乘梯权限管理与联动控制的稳定性。

这份清单非常专业&#xff0c;清晰地勾勒出了一套深度融入楼宇对讲系统的智能梯控解决方案。这不仅仅是设备的堆砌&#xff0c;更是一套通过协议对接和硬件联动&#xff0c;实现从“业主无感通行”到“访客精准授权”全场景覆盖的完整蓝图楼宇可视对讲门禁与梯控系统联动方案一…

Webpack从“配置到提速”,4步解决“打包慢、体积大”问题

一、数据绑定&#xff1a;别让模板变成“计算战场”1. 复杂逻辑抽离到计算属性问题&#xff1a;模板中写 {{ user.age > 18 ? 成年 : 未成年 }} 等复杂表达式&#xff0c;会导致模板臃肿且难以维护。 解决方案&#xff1a;用 computed 封装逻辑&#xff0c;兼具缓存特性&am…

机器人系统ros2期末速通2

6. Action&#xff08;动作&#xff09;&#xff1a;带反馈、可取消的长任务6.1 核心概念&#xff08;先搞懂是什么&#xff09;Action 是 ROS2 里专门处理耗时久、需要中间反馈、还能随时取消的任务的通信方式。专业名词拆解&#xff1a;Goal&#xff08;目标&#xff09;&…

拼多多春节加班费热议背后,近屿智能给出了另一份高薪答案

春节临近&#xff0c;你是否也正陷入“年后再说”的循环&#xff1f;当大多数人在为年终琐事分心时&#xff0c;有一群人&#xff0c;却在默默积累着“节后爆发”的资本——他们关注的不是加班补贴&#xff0c;而是如何让自己的技能&#xff0c;配得上更高的估值。一、高薪加班…

[特殊字符][特殊字符][特殊字符][特殊字符],拍一拍解锁快乐开挂版

拍了拍我的小肚子 &#x1f437;肥肉退退退₋₉₉₉拍了拍我的摸鱼手 &#x1f41f;带薪快乐10086拍了拍我的奶茶杯 &#x1f964;吨吨吨喝不胖✨拍了拍我的钱包 &#x1f911;空空如也但暴富在路上拍了拍我的闹钟 ⏰迟到不存在∞拍了拍我的老板说&#xff1a;放假啦快冲&#…

智能地板:AI Agent的室内活动模式分析

智能地板&#xff1a;AI Agent的室内活动模式分析关键词&#xff1a;智能地板、AI Agent、室内活动模式、数据分析、行为识别摘要&#xff1a;本文围绕智能地板与AI Agent的室内活动模式分析展开。详细介绍了智能地板的技术原理、AI Agent的工作机制&#xff0c;探讨了如何通过…

机器人系统ros2期末速通4

一、16. 调试工具链&#xff08;CLI rqt RViz2&#xff09;1. 核心概念&#xff08;系统里的实际样子&#xff09;CLI&#xff08;命令行工具&#xff09;&#xff1a;你在终端敲的 ROS 指令&#xff0c;是调试的 “基础武器”&#xff0c;比如查话题、查节点、查 TF 都靠它。…