当前位置: 首页 > news >正文

算法练习-合并两个有序数组

原题链接-合并两个有序数组

题目核心要求

  1. 有两个​​已经排好序(非递减)​​ 的数组 nums1nums2

  2. 要把 nums2合并到 nums1里面去。

  3. ​不能新开一个数组​​来存结果,必须直接修改 nums1

  4. nums1的长度足够大,后面用 0占好了位置。


方法一:直觉法(先合并,再排序)

这是最容易想到的方法,但​​不是最高效的​​),不过非常适合理解。

​思路:​

  1. 直接把 nums2里的所有元素,按顺序塞到 nums1末尾那些 0的位置上。

  2. 然后对整个 nums1调用 Python 自带的排序函数 sort()

​Python 代码:​

def merge(nums1, m, nums2, n):""":type nums1: List[int]:type m: int:type nums2: List[int]:type n: int:rtype: None Do not return anything, modify nums1 in-place instead."""# 1. 把 nums2 的所有元素,从 nums1 的第 m 个位置开始覆盖# 例如:m=3, 就从 nums1[3] 开始覆盖后面的0nums1[m:m+n] = nums2# 2. 直接对 nums1 进行原地排序nums1.sort()# 测试一下
nums1 = [1,2,3,0,0,0]
m = 3
nums2 = [2,5,6]
n = 3merge(nums1, m, nums2, n)
print(nums1) # 输出 [1, 2, 2, 3, 5, 6]

​缺点:​

我们没有利用“两个数组都已经排好序”这个条件,直接排序的时间复杂度是 O((m+n) * log(m+n)),不够高效。


方法二:双指针法(从后往前 - 推荐!)

这是​​最优解。它的核心思想是利用已知的“有序”条件,像拉链一样把两个数组合并起来。

​思路比喻:​

假设你有两叠已经从大到小排好序的卡片(nums1的有效部分和 nums2),现在你要把它们合并成一叠,并且只能从最上面(最大的数字)开始比较和放置。

  1. 设置三个“指针”:

    • p1:指向 nums1有效部分的最后一个元素(索引 m-1)。

    • p2:指向 nums2的最后一个元素(索引 n-1)。

    • p:指向 nums1数组的最后一个位置(索引 m+n-1),这是用来放最终结果的。

  2. ​从后往前​​比较 nums1[p1]nums2[p2]

    • 谁大,就把谁放到 nums1[p]的位置。

    • 然后,对应的指针 (p1p2) 和 p都向前移动一位。

  3. 重复步骤2,直到其中一个数组的所有元素都比较完。

  4. ​重要收尾​​:如果最后 nums2里还有剩余的元素(即 p2 >= 0),说明这些元素都是最小的,需要把它们按顺序复制到 nums1最前面的位置。

​为什么要从后往前?​

因为 nums1的后面是空闲的 0,从大到小放置不会覆盖掉 nums1前面还没比较到的有效数字。如果从前往后放,会覆盖数据,需要额外空间。

​Python 代码:​

def merge(nums1, m, nums2, n):# 初始化三个指针p1 = m - 1 # 指向 nums1 有效部分的末尾p2 = n - 1 # 指向 nums2 的末尾p = m + n - 1 # 指向 nums1 整个数组的末尾# 当两个数组都还有元素没比较时while p1 >= 0 and p2 >= 0:if nums1[p1] > nums2[p2]:# 如果 nums1 的元素大,把它放到后面nums1[p] = nums1[p1]p1 -= 1else:# 如果 nums2 的元素大(或相等),把它放到后面nums1[p] = nums2[p2]p2 -= 1p -= 1 # 每放一个元素,总指针前移一位# 收尾:如果 nums2 还有剩余元素(意味着这些是最小的)# 直接把它们复制到 nums1 的前面# 如果 p2 < 0,说明 nums2 已经全部处理完,这个循环不会执行nums1[:p2 + 1] = nums2[:p2 + 1]# 测试
nums1 = [1,2,3,0,0,0]
m = 3
nums2 = [2,5,6]
n = 3merge(nums1, m, nums2, n)
print(nums1) # 输出 [1, 2, 2, 3, 5, 6]

​为什么最后要收尾?​

来看一个例子:nums1 = [4, 5, 6, 0, 0, 0], nums2 = [1, 2, 3]

  • 按照从后往前比较:

    • 6>3-> 放6

    • 5>3-> 放5

    • 4>3-> 放4

  • 此时 p1已经变成 -1,循环结束。但 nums2里还剩 [1, 2, 3]这三个元素没处理!

  • 所以我们需要 nums1[:p2 + 1] = nums2[:p2 + 1]这行代码,把 nums2剩下的所有元素直接放到 nums1的最开头。

​复杂度分析:​

  • ​时间复杂度:O(m+n)​​。我们只遍历了每个元素一次。

  • ​空间复杂度:O(1)​​。没有使用额外的数组空间,只用了几个变量。

总结

方法

思路

优点

缺点

推荐度

​先合并后排序​

直接把 nums2放进去,然后调用 sort()

代码极其简单,容易想到

没有利用有序条件,效率低

⭐⭐

​双指针(从后往前)​

像拉链一样,从最大的元素开始比较和放置

效率最高,利用了有序条件

思路稍微复杂一点

⭐⭐⭐⭐⭐

我建议:

  1. 先理解方法一的直觉思路。

  2. 再重点攻克方法二的双指针法,这是算法的核心思想,在很多其他问题中也会用到。

  3. 多画图模拟一下指针移动的过程,就会豁然开朗!

http://www.xdnf.cn/news/1372573.html

相关文章:

  • Java大厂面试全真模拟:从Spring Boot到微服务架构实战
  • HTML应用指南:利用GET请求获取中国银行人民币存款利率数据
  • 【系统架构设计(二)】系统工程与信息系统基础中:信息系统基础
  • 数据结构青铜到王者第四话---LinkedList与链表(1)
  • [Mysql数据库] 知识点总结3
  • 深度学习:卷积神经网络(CNN)
  • Docker中如何记录非交互式连接ssh用户操作的所有命令记录?
  • QT(QTableWidget)
  • 机器学习:前篇
  • Linux系统的网络管理(二)
  • SELinux相关介绍
  • 质押、ETF、财库三箭齐发:以太坊价值逻辑的重构与演进
  • [灵动微电子 霍尔FOC MM32BIN560C]从引脚到应用
  • Ubuntu操作系统下使用mysql、mongodb、redis
  • 系统架构设计师-【2025上半年论文题目分享】
  • 探寻跨语言统一真理及其对NLP的未来启示
  • Agent实战教程:LangGraph关于智能体的架构模式与核心概念
  • 知行——同为科技24周年庆典
  • 【软件测试面试】全网最全,自动化测试面试题总结大全(付答案)
  • 二维费用背包 分组背包
  • Git命令
  • 机器学习每日一题000-矩阵和向量的乘法python实现
  • 在Excel和WPS表格中输入分数的两种方法
  • Linux正则表达式
  • shiro进行解密
  • 如何才能使RISC V架构成为机器学习的核心
  • 【Modbus-TCP】linux为主机—PC为从机通信
  • Git工具
  • 【44页PPT】极简架构MES系统解决方案介绍(附下载方式)
  • 阿里云 ECS 可观测性最佳实践