合并两个有序数组

710 字
4 分钟
合并两个有序数组

题目链接:88. 合并两个有序数组 - 力扣(LeetCode)

  • 难度:简单
  • 标签:数组、双指针

题目描述#

Note

原题说明: 给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终结果应存储在数组 nums1 中。nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。

示例#

  • 输入: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
  • 输出: [1,2,2,3,5,6]

方案:逆向双指针(原地合并)#

核心思路: 如果从前往后合并,我们需要额外的空间来存储 nums1 的原始数据,否则会发生覆盖。但观察题目发现,nums1尾部是空的。

  1. 使用两个指针 ij 分别指向 nums1nums2 的有效数据末尾。
  2. 使用指针 k 指向 nums1 的真正末尾(m + n - 1)。
  3. 比较 nums1[i]nums2[j],将较大的数填入 nums1[k],并向前移动指针。
  4. 这种方式不需要额外空间,且不会覆盖掉还未比较的元素。

源码实现#

class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = m - 1; // nums1 的有效末尾
int j = n - 1; // nums2 的末尾
int k = m + n - 1; // nums1 的实际空间末尾
// 从后往前填充,避免覆盖原有数据
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[k--] = nums1[i--];
} else {
nums1[k--] = nums2[j--];
}
}
// 如果 nums2 还有剩余,将其全部拷贝到 nums1 前部
// 注意:如果 nums1 还有剩余则不需要处理,因为它们已经在正确的位置上了
while (j >= 0) {
nums1[k--] = nums2[j--];
}
}
};

复杂度分析#

  • 时间复杂度O(m+n)O(m + n)。其中 mmnn 分别是两个数组的长度。我们只需扫描两个数组各一次。
  • 空间复杂度O(1)O(1)。我们直接在 nums1 的预留空间上进行操作,没有使用额外空间。

总结#

  • 逆向思维:很多“数组原地修改”的问题,从后往前考虑往往能避开“覆盖原始数据”的陷阱。
  • 与链表合并的区别:本题与第 21 题(合并有序链表)思路一致,但数组的内存连续性允许我们利用尾部空闲空间进行优化。
  • 细节处理:最后的 while(j >= 0) 非常关键,它处理了 nums2 还有剩余而 nums1 已遍历完的情况。
Tip

“从后往前”是处理原地数组合并的黄金法则。掌握了这个技巧,你就掌握了此类问题的最优解!

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

合并两个有序数组
https://firefly-7a0.pages.dev/posts/leetcode_notes/88merge-sorted-array/
作者
lonelystar
发布于
2025-10-20
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-10-20,距今已过 191 天

部分内容可能已过时

评论区

Profile Image of the Author
LonelyStar
Hello, I'm LonelyStar.
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
119
分类
11
标签
346
总字数
226,548
运行时长
0
最后活动
0 天前

目录