一句话总结:
合并两个有序数组就像把两队按身高排队的小朋友合并成一队——每次从两队最前面挑最矮的放进新队伍,直到所有小朋友排好队!
一、双指针法(最优解)
原理: 用两个指针分别指向两个数组的起始位置,每次取较小的值放入新数组,直到所有元素处理完毕。
fun mergeSortedArrays(arr1: IntArray, arr2: IntArray): IntArray {
val merged = IntArray(arr1.size + arr2.size) // 创建新数组
var i = 0 // arr1的指针
var j = 0 // arr2的指针
var k = 0 // merged的指针
// 两队都还有人时,挑更小的放进去
while (i < arr1.size && j < arr2.size) {
merged[k++] = if (arr1[i] <= arr2[j]) arr1[i++] else arr2[j++]
}
// 处理剩下的arr1元素
while (i < arr1.size) merged[k++] = arr1[i++]
// 处理剩下的arr2元素
while (j < arr2.size) merged[k++] = arr2[j++]
return merged
}
时间复杂度: O(m + n) (m和n是两个数组的长度)
空间复杂度: O(m + n) (需要新数组存储结果)
二、测试用例
fun main() {
// 测试用例1:普通情况
val arr1 = intArrayOf(1, 3, 5)
val arr2 = intArrayOf(2, 4, 6)
println(mergeSortedArrays(arr1, arr2).contentToString())
// 输出 [1, 2, 3, 4, 5, 6]
// 测试用例2:一个数组为空
val emptyArr = intArrayOf()
val arr3 = intArrayOf(2, 4)
println(mergeSortedArrays(emptyArr, arr3).contentToString())
// 输出 [2, 4]
// 测试用例3:有重复元素
val arr4 = intArrayOf(1, 2, 2)
val arr5 = intArrayOf(2, 3)
println(mergeSortedArrays(arr4, arr5).contentToString())
// 输出 [1, 2, 2, 2, 3]
}
三、分步图解
初始状态:
arr1: [1, 3, 5] 指针i=0
arr2: [2, 4, 6] 指针j=0
第1步:选1(i=0)→ merged: [1]
第2步:选2(j=0)→ merged: [1, 2]
第3步:选3(i=1)→ merged: [1, 2, 3]
第4步:选4(j=1)→ merged: [1, 2, 3, 4]
第5步:选5(i=2)→ merged: [1, 2, 3, 4, 5]
最后把arr2剩下的6加入 → 完成!
四、其他方法对比
| 方法 | 时间复杂度 | 适用场景 |
|---|---|---|
| 双指针法 | O(m + n) | 最优解,推荐使用 |
| 合并后排序 | O((m+n)log(m+n)) | 代码简单但效率低 |
五、常见问题
Q1:如果输入数组无序怎么办?
A:先排序再合并,但时间复杂度会增加(取决于排序算法)。
Q2:能否原地合并节省空间?
A:如果arr1预先留有足够空间(如LeetCode 88题),可以逆向双指针,但本题要求返回新数组。
口诀:
有序数组合并不难,
双指针法走前端。
你一个来我一个,
谁小谁进新家园!