leetcode 面试经典 150 题(1/150) 88.合并两个有序数组

82 阅读2分钟

题目描述

给定两个按非递减顺序排列的整数数组 nums1nums2,其中 nums1 的有效长度为 mnums2 的有效长度为 n。要求将 nums2 合并到 nums1 中,使合并后的数组依然保持非递减顺序。nums1 的总长度为 m + n,末尾填充 0 以保证空间足够。

算法思路

核心思想:从后向前填充,避免覆盖未处理的元素。

具体步骤

  1. 初始化指针

    • p1:指向 nums1 有效部分的末尾(索引 m-1)。
    • p2:指向 nums2 的末尾(索引 n-1)。
    • last:指向 nums1 的最后一个位置(索引 m+n-1)。
  2. 逆向双指针遍历

    • 比较 nums1[p1]nums2[p2],将较大的值放入 nums1[last]
    • 每放入一个元素,对应的指针(p1p2)和 last 向前移动一位。
    • 终止条件:当 nums2 的所有元素都处理完毕(p2 < 0)。
  3. 处理剩余元素

    • nums1 的元素先处理完,直接将 nums2 剩余元素依次填充到 nums1 前端。

过程示例

以示例 nums1 = [1,2,3,0,0,0](m=3),nums2 = [2,5,6](n=3)为例:

步骤p1 值p2 值last 位置操作nums1 状态
初始2 (3)2 (6)last=5[1,2,3,0,0,0]
122取6 → nums1[5]=6[1,2,3,0,0,6](p2→1)
221 (5)取5 → nums1[4]=5[1,2,3,0,5,6](p2→0)
320 (2)取3 → nums1[3]=3[1,2,3,3,5,6](p1→1)
41 (2)0取2 → nums1[2]=2[1,2,2,3,5,6](p2→-1)
终止--nums2处理完毕合并完成

复杂度分析

  • 时间复杂度:O(m + n)。每个元素只需比较和赋值一次。
  • 空间复杂度:O(1)。原地修改,未使用额外空间。

代码实现

func merge(nums1 []int, m int, nums2 []int, n int) {
    p1 := m - 1
    p2 := n - 1
    last := len(nums1) - 1

    for p2 >= 0 {
        if p1 >= 0 && nums1[p1] > nums2[p2] {
            nums1[last] = nums1[p1]
            p1--
        } else {
            nums1[last] = nums2[p2]
            p2--
        }
        last--
    }
}

关键点总结

  1. 逆向操作:避免了从头开始合并时的元素覆盖问题。
  2. 终止条件:当 nums2 全部合并后,剩余 nums1 的元素已有序,无需处理。
  3. 边界处理:当 m=0 时,直接将 nums2 复制到 nums1 中。