AC109-合并两个递增有序表为一个递减有序表¶
实现代码¶
算法执行过程图解¶
假设:
- 表 A = [1, 3, 5, 7],长度为 4;
- 表 B = [2, 4, 6, 8, 10],长度为 5。
目标是将 A 和 B 合并为一个递减有序表 C。
初始状态¶
第一步:比较 A[3] = 7 和 B[4] = 10¶
7 < 10,将10放入C。 更新j = 3。
第二步:比较 A[3] = 7 和 B[3] = 8¶
7 < 8,将8放入C。 更新j = 2。
第三步:比较 A[3] = 7 和 B[2] = 6¶
7 > 6,将7放入C。 更新i = 2。
第四步:继续处理剩余元素¶
依次比较并插入:
- A[2] = 5 vs B[2] = 6 → 插入 6;
- A[2] = 5 vs B[1] = 4 → 插入 5;
- A[1] = 3 vs B[1] = 4 → 插入 4;
- A[1] = 3 vs B[0] = 2 → 插入 3;
- A[0] = 1 vs B[0] = 2 → 插入 2;
- 最后插入 A[0] = 1。
最终结果:
| Text Only | |
|---|---|
复杂度分析¶
时间复杂度:O(M + N)¶
- 主循环:
- 每次比较
A[i]和B[j],选择较大的放入C。 - 每次操作后,
i或j减少 1。 -
总共最多进行
M + N次比较。 -
剩余元素处理:
- 如果
A或B中还有剩余元素,则直接复制到C。 -
最多需要
M或N次操作。 -
总时间复杂度:O(M + N)。
空间复杂度:O(1)¶
- 额外变量:
- 使用了常数个额外变量(
i,j,k)。 -
没有使用额外的存储空间。
-
原地操作:
-
直接在
C中存储结果。 -
总空间复杂度:O(1)。
关键知识点延伸¶
1. 算法核心思想¶
双指针技巧¶
- 逆序遍历:从
A和B的末尾开始,确保每次插入的是当前的最大值。 - 贪心策略:每次选择较大的元素放入
C,保证结果递减有序。
原地修改的优势¶
- 不需要额外的数组或数据结构。
- 直接在
C中按顺序存储结果。
2. 特殊情况处理¶
2.1 空表处理¶
- 如果两个输入表都为空,则输出表也为空。2.2 一个表为空¶
- 如果其中一个表为空,则直接将另一个表逆序复制到C。
3. 扩展应用¶
3.1 合并为递增有序表¶
如果要求合并为递增有序表,只需调整遍历方向:
3.2 归并排序的核心¶
该算法实际上是归并排序中“合并”步骤的一个变种。在归并排序中,通常合并为递增有序表,而这里改为递减有序表。
4. 边界条件与验证¶
4.1 边界条件¶
- 输入表为空或只有一个元素时,算法是否正确?
- 输入表长度不同时,算法是否能正确处理?
4.2 验证方法¶
- 测试用例包括:
- 两个空表。
- 一个空表,一个非空表。
- 两个长度相同的表。
- 两个长度不同的表。
- 表中包含重复元素的情况。
算法特点总结¶
- 高效性:时间复杂度 O(M + N),空间复杂度 O(1)。
- 简洁性:实现简单,逻辑清晰。
- 适用性:特别适合处理有序表的合并问题。
- 扩展性:可以轻松扩展为其他形式的合并(如递增有序表)。
记忆要点¶
- 逆序遍历:从两个表的末尾开始,确保每次插入的是当前的最大值。
- 贪心策略:每次选择较大的元素放入结果表。
- 双指针技巧:分别指向两个表的当前处理位置。
- 边界处理:注意空表和剩余元素的处理。
- 时间效率:线性时间 O(M + N),空间复杂度 O(1)。