力扣88题:合并两个有序数组

力扣88题:合并两个有序数组

题目描述

给定两个按非递减顺序排列的整数数组 nums1nums2,以及它们的长度 mn,要求将 nums2 合并到 nums1,使得合并后的数组仍按非递减顺序排列。

输入与输出

示例 1

plaintext 复制代码
输入:nums1 = [1,2,3,0,0,0], m = 3
      nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]

示例 2

plaintext 复制代码
输入:nums1 = [1], m = 1
      nums2 = [], n = 0
输出:[1]

示例 3

plaintext 复制代码
输入:nums1 = [0], m = 0
      nums2 = [1], n = 1
输出:[1]

算法思路

1. 问题分析

题目要求我们原地合并两个数组:

  • nums1 的后半部分预留了足够的空间(大小为 m + n m + n m+n)。
  • nums1nums2 已经是有序的。

2. 双指针逆向合并

我们从两个数组的尾部开始比较,选择较大的元素放入 nums1 的末尾。具体步骤如下:

2.1 初始化指针
  • 定义指针 p1:指向 nums1 的有效元素的末尾(即索引 m − 1 m - 1 m−1)。
  • 定义指针 p2:指向 nums2 的末尾(即索引 n − 1 n - 1 n−1)。
  • 定义指针 p:指向 nums1 的总末尾(即索引 m + n − 1 m + n - 1 m+n−1)。
2.2 比较与插入
  • 如果 nums1[p1] > nums2[p2],将 nums1[p1] 放入 nums1[p],并移动 p1p
  • 如果 nums1[p1] <= nums2[p2],将 nums2[p2] 放入 nums1[p],并移动 p2p
2.3 拷贝剩余元素
  • 如果 nums2 中还有未处理的元素,直接将它们拷贝到 nums1 的前面。
  • 如果 nums1 中还有未处理的元素,则无需额外操作。
2.4 循环终止条件
  • p1 < 0p2 < 0 时,循环结束。

代码实现

以下是修正后的完整代码:

c 复制代码
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int i = nums1Size - 1; // 从 nums1 的尾部开始填充
    while (m > 0 || n > 0) {
        if (n > 0 && (m == 0 || nums1[m - 1] < nums2[n - 1])) {
            nums1[i--] = nums2[--n];
        } else {
            nums1[i--] = nums1[--m];
        }
    }
}

代码详解

1. 初始化指针

定义三个指针:

  • p1 = m - 1:指向 nums1 有效部分的末尾。
  • p2 = n - 1:指向 nums2 的末尾。
  • p = m + n - 1:指向 nums1 的尾部。

2. 从尾部向前合并

通过比较 nums1[p1]nums2[p2],将较大的元素放入 nums1[p],并更新指针。以下是操作逻辑:

c 复制代码
if (n > 0 && (m == 0 || nums1[m - 1] < nums2[n - 1])) {
    nums1[p--] = nums2[--n];
} else {
    nums1[p--] = nums1[--m];
}

3. 拷贝剩余的 nums2

如果 nums2 中还有未处理的元素,直接拷贝:

c 复制代码
while (n > 0) {
    nums1[p--] = nums2[--n];
}

复杂度分析

时间复杂度

  • 遍历数组时,每次比较、移动只需 O ( 1 ) O(1) O(1) 时间,总体复杂度为 O ( m + n ) O(m + n) O(m+n)。

空间复杂度

  • 使用了常量级的额外空间,复杂度为 O ( 1 ) O(1) O(1)。

测试用例

测试用例 1

输入

plaintext 复制代码
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出

plaintext 复制代码
[1,2,2,3,5,6]

测试用例 2

输入

plaintext 复制代码
nums1 = [1], m = 1
nums2 = [], n = 0

输出

plaintext 复制代码
[1]

测试用例 3

输入

plaintext 复制代码
nums1 = [0], m = 0
nums2 = [1], n = 1

输出

plaintext 复制代码
[1]

测试用例 4

输入

plaintext 复制代码
nums1 = [2,2,2,0,0,0], m = 3
nums2 = [2,2,2], n = 3

输出

plaintext 复制代码
[2,2,2,2,2,2]
相关推荐
拾光Ծ5 分钟前
【优选算法】双指针算法:专题一
数据结构·c++·算法
Watermelo6176 分钟前
【前端实战】从 try-catch 回调到链式调用:一种更优雅的 async/await 错误处理方案
前端·javascript·网络·vue.js·算法·vue·用户体验
MSTcheng.6 分钟前
【C++】如何快速实现一棵支持key或key-value的二叉搜索树?关键技巧一文掌握!
开发语言·c++·算法·二叉搜索树
野生风长9 分钟前
从零开始的c语言:指针高级应用(下)(回调函数,qsort函数模拟实现, strlen和sizeof)
java·c语言·开发语言·c++·算法
Dingdangcat8614 分钟前
YOLO12-ADown改进算法:两轮车辆行驶环境中的多目标检测与识别_1
算法·目标检测·目标跟踪
倔强的石头10614 分钟前
Linux 进程深度解析(三):调度算法、优先级调整与进程资源回收(wait与waitpid)
linux·服务器·算法
LYFlied14 分钟前
【一句话概括】Vue2 和 Vue3 的 diff 算法区别
前端·vue.js·算法·diff
s090713619 分钟前
多波束声呐 FPGA 信号处理链路介绍
算法·fpga开发·信号处理·声呐
User_芊芊君子23 分钟前
【LeetCode经典题解】:从前序和中序遍历构建二叉树详解
算法·leetcode·职场和发展
C雨后彩虹24 分钟前
虚拟理财游戏
java·数据结构·算法·华为·面试