Java中无法真正原地合并两个独立有序数组,因数组长度固定且不可扩容;所谓“原地归并”仅适用于nums1尾部有足够空位的场景,通过逆向双指针将nums2元素填入空位,时间O(m+n)、空间O(1)。

Java 中无法真正实现“原地归并”两个已排序数组(如 int[]),因为数组长度固定,合并后元素总数增加,必然需要额外空间存储结果。所谓“高效原地归并”,通常指**不使用额外的 O(n+m) 辅助数组**,但允许使用 O(1) 额外空间,并在**一个已有足够容量的目标数组上完成合并**——这正是 LeetCode 88. 合并两个有序数组 的经典场景。
前提:目标数组有足够空位
假设数组 nums1 长度为 m + n,其中前 m 个元素有效、后 n 个位置为空;nums2 长度为 n,全部有效。此时可从**尾部开始逆向归并**,避免覆盖未处理元素。
- 用三个指针:
i指向nums1有效末尾(m-1),j指向nums2末尾(n-1),k指向nums1真实末尾(m+n-1) - 比较
nums1[i]和nums2[j],将较大者填入nums1[k],对应指针前移 - 若
nums2还有剩余(j >= 0),直接复制到nums1前部;nums1剩余部分已在正确位置,无需操作
代码实现(O(m+n) 时间,O(1) 空间)
// nums1.length == m + n,nums1 有 m 个有效数,后 n 位空;nums2.length == n
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1, j = n - 1, k = m + n - 1;
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[k--] = nums1[i--];
} else {
nums1[k--] = nums2[j--];
}
}
while (j >= 0) { // nums2 还有剩余
nums1[k--] = nums2[j--];
}
// i >= 0 时无需处理:nums1 剩余元素已在正确位置
}为什么不能“完全原地”合并两个独立数组?
若给定两个独立、长度固定的数组 a[ ] 和 b[ ],且不允许创建新数组,则:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- Java 数组是不可变长度对象,无法动态扩容
- 任何合并操作都需输出到某处,若强制写回其中一个数组,必然导致原始数据被覆盖或丢失
- 不存在类似 C 语言中通过指针重解释内存的底层操作
因此,“原地”在此语境下特指复用已有冗余空间 + 逆向遍历避免覆盖,而非字面意义的零额外空间。
如果必须合并两个独立数组(无冗余空间)
只能接受 O(m+n) 额外空间:
- 创建新数组
res = new int[m + n] - 双指针正向归并(标准归并排序 merge 步骤)
- 时间 O(m+n),空间 O(m+n)
这是通用、安全、清晰的做法,也是实际开发中最推荐的方式。

















