题目描述
给定两个按非递减顺序排列的整数数组 nums1 和 nums2,其中 nums1 的有效长度为 m,nums2 的有效长度为 n。要求将 nums2 合并到 nums1 中,使合并后的数组依然保持非递减顺序。nums1 的总长度为 m + n,末尾填充 0 以保证空间足够。
算法思路
核心思想:从后向前填充,避免覆盖未处理的元素。
具体步骤
-
初始化指针:
p1:指向nums1有效部分的末尾(索引m-1)。p2:指向nums2的末尾(索引n-1)。last:指向nums1的最后一个位置(索引m+n-1)。
-
逆向双指针遍历:
- 比较
nums1[p1]和nums2[p2],将较大的值放入nums1[last]。 - 每放入一个元素,对应的指针(
p1或p2)和last向前移动一位。 - 终止条件:当
nums2的所有元素都处理完毕(p2 < 0)。
- 比较
-
处理剩余元素:
- 若
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] |
| 1 | 2 | 2 | 取6 → nums1[5]=6 | [1,2,3,0,0,6](p2→1) |
| 2 | 2 | 1 (5) | 取5 → nums1[4]=5 | [1,2,3,0,5,6](p2→0) |
| 3 | 2 | 0 (2) | 取3 → nums1[3]=3 | [1,2,3,3,5,6](p1→1) |
| 4 | 1 (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--
}
}
关键点总结
- 逆向操作:避免了从头开始合并时的元素覆盖问题。
- 终止条件:当
nums2全部合并后,剩余nums1的元素已有序,无需处理。 - 边界处理:当
m=0时,直接将nums2复制到nums1中。