当前位置: 首页 > 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.dtcms.com/a/351749.html

相关文章:

  • 表格比对的实现
  • 如何确定哪些层应添加适配器(Adapter)?(58)
  • 餐中服务:藏在菜香里的 “情感传递术”
  • Java继承与虚方法详解
  • 掌握常用CSS样式:从基础到实战的全面指南
  • 从0开始学习Java+AI知识点总结-26.web实战(Springboot原理)
  • 产品经理成长手册(2)——产品文档能力
  • 14、RocketMQ生产环境如何优化
  • Linux查看服务器内存、磁盘、cpu、网络占用、端口占用情况
  • THM El Bandito
  • 设计模式学习笔记-----抽象责任链模式
  • 常见的设计模式
  • 深度学习篇---1*1卷积核的升维/降维
  • Unity笔记(七)——四元数、延迟函数、协同程序
  • 【Linux】Keepalived + Nginx高可用方案
  • [pilot智驾系统] 驾驶员监控守护进程(dmonitoringd)
  • 从代码学习深度强化学习 - 多智能体强化学习 IPPO PyTorch版
  • pytorch_grad_cam 库学习笔记——基类ActivationsAndGradient
  • vue2 和 vue3 生命周期的区别
  • 【Android】不同系统API版本_如何进行兼容性配置
  • 2014-2024高教社杯全国大学生数学建模竞赛赛题汇总预览分析
  • VMDK 文件
  • 软考-系统架构设计师 计算机系统基础知识详细讲解二
  • springcloud篇5-微服务保护(Sentinel)
  • Spring Boot mybatis-plus 多数据源配置
  • 【CVE-2025-5419】(内附EXP) Google Chrome 越界读写漏洞【内附EXP】
  • Kafka面试精讲 Day 1:Kafka核心概念与分布式架构
  • Elasticsearch中的协调节点
  • 详解kafka基础(一)
  • JavaScript常用的算法详解