AC108-合并两个递增有序表¶
实现代码¶
算法执行过程图解¶
假设:
- A:[1, 3, 5, 7]
- B:[2, 4, 6, 8]
- C:初始为空
初始状态¶
第一步:比较 A[0]=1 和 B[0]=2¶
1 < 2,将1放入C。
第二步:比较 A[1]=3 和 B[0]=2¶
2 < 3,将2放入C。
第三步:继续比较¶
- 比较
A[1]=3和B[1]=4→ 放入3。 - 比较
A[2]=5和B[1]=4→ 放入4。 - 比较
A[2]=5和B[2]=6→ 放入5。 - 比较
A[3]=7和B[2]=6→ 放入6。 - 比较
A[3]=7和B[3]=8→ 放入7。
最终状态¶
A和B均已遍历完毕。- 将
B[3]=8放入C。Text Only
复杂度分析¶
时间复杂度:O(M + N)¶
- 主循环:
- 每次比较后,至少有一个指针 (
i或j) 前进。 -
总比较次数最多为
M + N(两个表的总长度)。 -
处理剩余元素:
- 如果一个表先遍历完,另一个表的剩余部分直接复制。
-
这部分操作的时间复杂度为 O(剩余元素个数)。
-
结论:时间复杂度为 O(M + N)。
空间复杂度:O(1)¶
- 额外变量:
- 只使用了常数个额外变量(
i,j,k)。 -
没有使用额外的存储空间。
-
输出数组:
-
结果存储在
C中,但这是必要的输出,不计入额外空间。 -
结论:空间复杂度为 O(1)。
关键知识点延伸¶
1. 算法核心思想¶
双指针技巧¶
- 指针
i:用于遍历表A。 - 指针
j:用于遍历表B。 - 指针
k:用于标记合并结果表C的写入位置。 - 利用有序性:由于
A和B已排序,只需依次比较当前元素即可。
原地合并的优势¶
- 不需要额外的临时数组。
- 直接将结果写入目标数组
C。
2. 特殊情况处理¶
2.1 其中一个表为空¶
- 如果
A为空,则直接将B的所有元素复制到C。 - 如果
B为空,则直接将A的所有元素复制到C。
2.2 表中有重复元素¶
- 算法会保留所有重复元素,因为没有去重逻辑。
- 如果需要去重,可以在比较时增加判断条件。
3. 扩展应用¶
3.1 合并 K 个有序表¶
可以扩展为合并多个有序表:
| C | |
|---|---|
3.2 合并两个链表¶
如果是链表结构,可以使用类似的方法:
4. 与归并排序的关系¶
该算法是归并排序的核心步骤之一: - 归并排序通过递归将数组分解为单个元素的子数组。 - 在合并阶段,使用类似的双指针方法将两个有序子数组合并为一个有序数组。
算法特点总结¶
- 高效性:时间复杂度 O(M + N),空间复杂度 O(1)。
- 稳定性:保持元素的相对顺序。
- 简洁性:实现简单,逻辑清晰。
- 通用性:可用于链表、数组等多种数据结构。
- 可扩展性:可以扩展到合并多个有序表。
记忆要点¶
- 双指针技巧:
i遍历A,j遍历B,k写入C。 - 核心思想:利用有序性,每次取较小的元素放入结果表。
- 边界处理:注意其中一个表遍历完后,直接复制另一个表的剩余部分。
- 时间效率:线性时间 O(M + N),优于无序表合并的 O((M + N) log (M + N))。
- 空间效率:原地操作,空间复杂度 O(1)。