当前位置: 首页 > news >正文

从暴力到最优——力扣88.合并两个有序数组

力扣88.合并两个有序数组

在这里插入图片描述


合并两个有序数组题解(详解三种方法:直接合并、双指针正序、双指针逆序)

一、题目回顾

给定两个按 非递减顺序 排列的整数数组 nums1nums2,其中:

  • nums1 的前 m 个元素为有效数据,后 n 个元素为 0(预留空间);
  • nums2 的长度为 n
  • 要求将 nums2 合并到 nums1 中,使得 nums1 成为一个新的有序数组;
  • 函数不需要返回值,直接在原地修改 nums1

示例

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

二、题目分析

题目要求:

  • 数组非递减(即升序,可有重复);
  • 在原数组 nums1 中合并结果;
  • 空间有限,尽可能在 O(1) 额外空间内完成;
  • 时间复杂度要求为 O(m + n)。

核心挑战在于:

如何避免提前覆盖掉 nums1 的有效元素。

如果我们从前往后直接合并,当 nums1 较小时可能会被覆盖。因此,需要考虑从后往前合并的策略。


三、方法一:直接合并 + 排序(简单但效率不高)

思路

  1. 先将 nums2 中的元素直接放入 nums1 的尾部空位;
  2. 调用排序函数(如 Arrays.sort)对整个 nums1 排序。

代码实现

import java.util.Arrays;class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {for (int i = 0; i < n; i++) {nums1[m + i] = nums2[i];}Arrays.sort(nums1);}
}

在这里插入图片描述

复杂度分析

  • 时间复杂度:O((m + n) log(m + n))
  • 空间复杂度:O(1)

优缺点

  • 优点:实现简单,几行代码即可;
  • 缺点:没有利用数组原有的有序性,不符合题目的“进阶要求”。

四、方法二:双指针正序合并(需要额外数组)

思路

  1. 创建一个新数组 sorted
  2. 使用两个指针 p1p2 分别指向 nums1nums2
  3. 比较两个指针所指的元素,将较小的放入 sorted
  4. 当某一方到达末尾,直接拷贝另一方剩余元素;
  5. 最后将 sorted 的内容拷回 nums1

代码实现

class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {int[] sorted = new int[m + n];int p1 = 0, p2 = 0, p = 0;while (p1 < m && p2 < n) {if (nums1[p1] <= nums2[p2]) {sorted[p++] = nums1[p1++];} else {sorted[p++] = nums2[p2++];}}while (p1 < m) sorted[p++] = nums1[p1++];while (p2 < n) sorted[p++] = nums2[p2++];System.arraycopy(sorted, 0, nums1, 0, m + n);}
}

在这里插入图片描述

复杂度分析

  • 时间复杂度:O(m + n)
  • 空间复杂度:O(m + n)

优缺点

  • 优点:清晰直观;
  • 缺点:使用了额外数组,空间复杂度较高。

五、方法三:双指针逆序合并(最优解)

核心思想

从后往前合并可以避免覆盖问题:

  1. 设三个指针:

    • p1 = m - 1 指向 nums1 的最后一个有效元素;
    • p2 = n - 1 指向 nums2 的最后一个元素;
    • p = m + n - 1 指向 nums1 的最后一个位置(总长度)。
  2. 比较 nums1[p1]nums2[p2]

    • 较大的放到 nums1[p]
    • 指针左移;
  3. 重复直到 p2 < 0;

  4. nums1 剩余部分无需处理;
    nums2 还有剩余,拷贝剩下的部分。

图示(示例)

nums1 = [1,2,3,0,0,0]
nums2 = [2,5,6]
初始:
p1=2, p2=2, p=5比较 3 vs 6 → 6 放到 nums1[5]
nums1 = [1,2,3,0,0,6]继续比较 3 vs 5 → 5 放到 nums1[4]
nums1 = [1,2,3,0,5,6]继续比较 3 vs 2 → 3 放到 nums1[3]
nums1 = [1,2,3,3,5,6]最后将 nums2 剩下的 [2] 放入。

代码实现

class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {int p1 = m - 1, p2 = n - 1, p = m + n - 1;while (p1 >= 0 && p2 >= 0) {if (nums1[p1] > nums2[p2]) {nums1[p--] = nums1[p1--];} else {nums1[p--] = nums2[p2--];}}// 如果 nums2 还有剩余,拷贝到前面while (p2 >= 0) {nums1[p--] = nums2[p2--];}}
}

在这里插入图片描述


复杂度分析

  • 时间复杂度:O(m + n)
  • 空间复杂度:O(1)
  • 不需要额外空间,完全原地合并。

六、三种方法对比

方法思路时间复杂度空间复杂度优点缺点
1. 直接合并排序简单粗暴O((m+n)log(m+n))O(1)简洁效率不高
2. 双指针正序从前往后合并O(m+n)O(m+n)逻辑直观需要额外数组
3. 双指针逆序从后往前合并O(m+n)O(1)原地合并,最优稍复杂但经典

七、总结

  • 核心思想: 充分利用已排序数组的特性;
  • 关键技巧: 从尾部开始合并,避免元素覆盖;
  • 最优实现: 双指针逆序法(O(m + n) 时间,O(1) 空间)。

http://www.dtcms.com/a/507178.html

相关文章:

  • C语言——回调函数的典型示例(分析详解)
  • 雷州网站建设公司网站备案半身照
  • 【AI 风向标】gpt-oss20b 模型测试与评估报告(2025-08-21)
  • Java MyBatis(二)--- 多表查询,# 和 $的区别,SQL注入,数据库连接池,动态SQL
  • 深圳小企业网站建设vs做网站怎么放视频
  • 企业 做网站云虚拟主机搭建网站
  • PHP实现企业微信 会话存档功能
  • centos 7.9 编译安装 freeswitch 1.10.12
  • FT32A103RDAT3是什么芯片?车规级32位国产MCU可替代STM32F103RD
  • uni-app从后端返回的富文本中的视频截取一帧为封面
  • 若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
  • Linux 服务器安全巡检与加固:从命令到实操(CentOS/Ubuntu 通用)
  • 网站如何让百度收录官网seo是什么意思
  • STM32U5G9J-DK2开发板获取RAM占用
  • 从架构到运营:AIOps与O-AA™ 如何实现智能化企业运营
  • 徐州手机网站定制公司哪家好西安大型网站制作
  • 【Day 80】Linux-NAS 和 SAN 存储
  • C++可变参数模板
  • Python下载实战技巧的技术文章大纲
  • PostgreSQL高级特性解析:窗口函数与CTE
  • OpenBMC: BmcWeb处理WebScoket2 产生WebSocket对象
  • 构建AI智能体:六十九、Bootstrap采样在大模型评估中的应用:从置信区间到模型稳定性
  • 图论基础:探索节点与关系的复杂网络
  • 免费建网站 建站之星百度指数免费添加
  • python如何写数据到excel示例
  • Spring Cloud - Spring Cloud 注册中心与服务提供者(Spring Cloud Eureka 概述、微服务快速入门、微服务应用实例)
  • 测试经验分享,登录功能+购物车+限时秒杀(测试点)汇总
  • 腾讯云TVP走进美的,共探智能制造新范式
  • OpenAI 的 Sora 2来了:一场创意革命与失控的狂欢
  • 直播预告 | 时序数据赋能核电数字化转型,TDengine 引领创新新范式