双指针合并两个有序数组的标准做法是:升序时用std::merge(需预分配空间)或手写从前向后归并;降序时需指定greater<int>比较器;原地合并(如LeetCode 88)必须从后往前,用三指针避免覆盖。

用双指针合并两个有序数组(C++标准做法)
直接用 std::merge 最省事,但前提是两个源数组必须是升序且已排好——它不检查顺序,只做归并。如果你自己手写,核心就是维护两个指针分别指向两数组当前待比较元素,每次取较小者填入结果数组。
- 注意目标数组必须预留足够空间,否则越界;若原地合并(如 LeetCode 88 题),需从后往前填,避免覆盖未处理元素
-
std::merge要求输入迭代器支持随机访问或至少前向遍历,std::vector没问题,但std::list需用其自带的merge()成员函数 - 时间复杂度固定为
O(m + n),空间复杂度取决于是否新建容器:新建则O(m + n),原地则O(1)(不含输出空间)
std::merge 的典型调用方式和常见错误
别漏掉第三个迭代器参数——它是输出区间的起始位置,不是长度。最常错的是传错 back_inserter 或没预留空间导致写入野地址。
vector<int> a = {1, 3, 5};
vector<int> b = {2, 4, 6, 8};
vector<int> res(a.size() + b.size()); // 必须预先分配!
merge(a.begin(), a.end(), b.begin(), b.end(), res.begin());
// res 现在是 {1,2,3,4,5,6,8}
- 如果用
back_inserter(res),res可以是空 vector,但插入效率略低(多次 realloc) - 若数组是降序,不能直接用
std::merge,得先 reverse 或改写比较器:merge(..., greater<int>{}) - 编译报错
"no matching function for call to 'merge'"多半是迭代器类型不匹配,比如混用了const_iterator和iterator
原地合并(nums1 有足够尾部空间)怎么避免覆盖
LeetCode 88 题场景:nums1 长度为 m + n,前 m 个有效,后 n 个为占位 0。这时必须从后往前归并,用三个指针:i 指向 nums1 有效尾,j 指向 nums2 尾,k 指向 nums1 整体尾。
- 只要
i >= 0且j >= 0,就比较nums1[i]和nums2[j],大的填到nums1[k],对应指针前移 - 若
j < 0,说明nums2已空,nums1剩余部分不用动(本身有序) - 若
i < 0,说明nums1有效部分已空,需把nums2[0..j]全拷过去——这是唯一需要补拷的分支
用 array<T, N> 合并时要注意尺寸硬编码
std::array 是栈上固定大小容器,合并后新数组大小必须在编译期确定。你不能靠运行时算出总长再声明,得提前知道 m 和 n。
立即学习“C++免费学习笔记(深入)”;
- 例如
array<int, 5> a = {1,3,5,0,0}; array<int, 4> b = {2,4,6,8};,合并目标只能是array<int, 9> - 没法像
vector那样用resize(),所有尺寸都得写死,灵活性差,适合嵌入式等确定尺寸场景 - 如果强行用
std::merge到array,务必确认目标array的begin()到end()足够容纳,否则行为未定义
边界判断比看起来麻烦,尤其是原地合并时 i、j、k 的初值和终止条件稍错一位,结果就全乱。手动实现建议先写清楚每个指针的含义,再推一遍小例子。


















