算法 - 合并两个有序数组
1. 题目
给你两个按非递减顺序排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n,分别表示 nums1 和 nums2 中的元素数目。
请你合并 nums2 到 nums1 中,使合并后的数组同样按非递减顺序排列。
注意:最终合并后数组不由函数返回,而是存储在数组 nums1 中。nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0,应忽略。nums2 的长度为 n。
示例:
1 | 输入: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 |
2. 解题思路
2.1 为什么不能从前往后双指针?
若从下标 0 开始比较写入 nums1,会覆盖掉 nums1 尚未读取的有效元素。除非先拷贝一份 nums1(额外 O(m) 空间)。
2.2 逆向双指针(从头填充 → 从尾填充,最优)
从后往前填:nums1 的尾部 [m+n-1] 是空的(全是 0 占位),把较大元素放到尾部就不会覆盖未处理数据。
三指针:
p1 = m-1、p2 = n-1、tail = m+n-1。每次比较
nums1[p1]与nums2[p2],把较大者放到tail,对应指针前移。当
p1 < 0时,把nums2剩余元素拷进 nums1 头部;当p2 < 0时 nums1 剩余部分本就在正确位置,无需处理。时间复杂度:O(m + n),空间复杂度:O(1)。
3. TypeScript 实现
1 | function merge( |
4. 面试延伸
- 核心技巧「从后往前」:同适用于「字符串原地替换 / 删除元素」等避免覆盖的场景,是原地合并的通用思路。
- 对比:合并两个有序链表 用 dummy head 顺序拼接;合并区间(Merge Intervals)则先排序再线性扫描。三者都是「有序归并」家族。
- 追问:为什么相等时先放 nums1?任意皆可,不影响正确性,只影响稳定性表述。
- 归并排序 merge 步骤正是此逻辑,可顺势聊排序稳定性。
难度:简单 | LeetCode 88 | 逆向双指针 / 归并