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

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

题目核心要求

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

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

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

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


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

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

​思路:​

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

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

​Python 代码:​

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] 开始覆盖后面的0
    nums1[m:m+n] = nums2
    
    # 2. 直接对 nums1 进行原地排序
    nums1.sort()

# 测试一下
nums1 = [1,2,3,0,0,0]
m = 3
nums2 = [2,5,6]
n = 3

merge(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 代码:​

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 -= 1
        else:
            # 如果 nums2 的元素大(或相等),把它放到后面
            nums1[p] = nums2[p2]
            p2 -= 1
        p -= 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 = 3

merge(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. 多画图模拟一下指针移动的过程,就会豁然开朗!

相关推荐
倔强青铜三7 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试
用户25191624271110 小时前
Python之语言特点
python
刘立军11 小时前
使用pyHugeGraph查询HugeGraph图数据
python·graphql
聚客AI12 小时前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm
数据智能老司机14 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
大怪v15 小时前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法
数据智能老司机15 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
c8i16 小时前
django中的FBV 和 CBV
python·django
c8i16 小时前
python中的闭包和装饰器
python
惯导马工17 小时前
【论文导读】ORB-SLAM3:An Accurate Open-Source Library for Visual, Visual-Inertial and
深度学习·算法