如何快速合并两个有序数组?

2023-11-07

前言

大家好,我是来自于「华为」「程序员小熊」。今天给大家带来一道与「数组」相关的题目,这道题同时也是字节、微软和亚马逊等互联网大厂的面试题,即力扣上的第 88 题-合并两个有序数组。

本文主要介绍「逆向双指针」的策略来解答此题,供大家参考,希望对大家有所帮助。

合并两个有序数组

题目描述

示例 1:

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

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
 

提示:

nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-10^9 <= nums1[i], nums2[i] <= 10^9

解题思路

合并两个「有序」数组,比较容易想到的策略主要有以下几种:

为了方便描述,假设长度更长的数组为 nums1,长度稍微短一点的数组为 nums2,下文也是一直遵循这种描述。

策略一:将 nums2 中的元素全部插入到 nums1 的尾部,然后对处理之后的 nums1 进行排序。

策略二:双指针法,先开辟一个新数组,长度为两个数组的长度之和,然后让两个指针分别指向两个数组的头部,比较这个两个指针指向的数组元素的值,将数值较小的放到新数组的头部,再将指向的数值较小的指针右移,继续比较,直到遍历完其中一个数组即可。

「复杂度分析」

【时间复杂度】:策略一是「O((n + m)lg(n + m))」,主要是合并之后再排序的时间复杂度;策略二是「O(n + m)」,主要是遍历两个数组的时间复杂度。

【空间复杂度】:策略一是「O(1)」,未开辟额外的存储空间;策略二是「O(n + m)」,额外开辟了长度为 m + n 的数组。

逆向双指针

从前面的分析可知,策略二相对于策略一来说,时间复杂度「更优」了,但开辟了「额外」的空间。

有没有方法能够将策略二的空间复杂度优化呢?答案是有的,由于题目明确告知了「可以假设 nums1 的空间大小等于 m + n」,因此可以利用这个条件将策略二的空间复杂度优化。具体如下栗子分析:

「举例」

假设 nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3,如下图示。

示例

按照题目要求,合并后的数组应该如下图示:

合并后的数组

先设置两个指针 p 和 q,分别指向两个数组的末尾,假设 k 为 两数组的长度,如下图示:

逆向双指针

比较 p 和 q 指向数组位置的元素值

将元素值较大的存放在 nums1[k] 中,并左移 k 和 q(指向的数值较大的指针)

以此类推,其处理的完整过程如下动图示

合并的完整动图

Show me the Code

「C」

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int p = m - 1;      // p 指向 nums1[m - 1] 
    int q = n - 1;      // q 指向 nums2[n - 1] 
    int k = m + n - 1;  // k 指向 nums1[m + n - 1] 

    /* nums1、nums2 其中一个未遍历完,不断比较 nums1[p] 和 nums1[q],更新 nums[k] */
    while (p >= 0 && q >= 0) {
        nums1[k--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--];                   
    }

    /* 若 n > m,nums1 遍历完成,将 nums2 中尚未遍历完的元素拷贝到 nums1 中 */
    while (q >= 0) {
        nums1[k--] = nums2[q--];
    }
}

「C++」

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
    int p = m - 1;     
    int q = n - 1;     
    int k = nums1.size() - 1;   
    while (p >= 0 && q >= 0) {
        nums1[k--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--];                   
    }

    while (q >= 0) {
        nums1[k--] = nums2[q--];
    }
}

「Java」

void merge(int[] nums1, int m, int[] nums2, int n) {
    int p = m - 1;     
    int q = n - 1;     
    int k = nums1.length - 1;   
    while (p >= 0 && q >= 0) {
        nums1[k--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--];                   
    }

    while (q >= 0) {
        nums1[k--] = nums2[q--];
    }
}

「Python3」

def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
    p, q, k = m - 1, n - 1, len(nums1) - 1      
    while p >= 0 and q >= 0:
        if nums1[p] > nums2[q]:
            nums1[k] = nums1[p]
            p -= 1
        else:
            nums1[k] = nums2[q]
            q -= 1
        k -= 1

    while q >= 0:
        nums1[k] = nums2[q]
        q -= 1
        k -= 1  

「Golang」

func merge(nums1 []int, m int, nums2 []int, n int)  {
    p, q, k := m - 1, n - 1, len(nums1) - 1      
    for p >= 0 && q >= 0 {
        if nums1[p] > nums2[q] {
            nums1[k] = nums1[p]
            p -= 1
        } else {
            nums1[k] = nums2[q]
            q -= 1
        }
        k -= 1
    }

    for q >= 0 {
        nums1[k] = nums2[q]
        q -= 1
        k -= 1 
    }
}

「复杂度分析」

时间复杂度:「O(n + m)」,需要遍历一遍两个数组。

空间复杂度:「O(1)」,未开辟额外的空间。

往期精彩回顾

最大子序和

你不可不会的几种移动零的方法

专业小偷才能盗取最大金额的现金

手撕腾讯面试题-乘积最大子数组

茫茫人海,如何快速找到合适的 ta?

你不可不会的几种移动零的方法(续集)

更多精彩

关注公众号「程序员小熊」

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何快速合并两个有序数组? 的相关文章

  • 图像识别最好的算法,图片相似度识别算法

    现在人脸识别最有效的算法是什么 最好的人脸识别系统在理想情况下比人类识别的表现要好的多 但是一旦环境情况变糟 系统的表现就差强人意了 而计算机科学家们当然是非常想要开发出一种算法 在各种情况下都能够表现优异 现在 中国香港大学的汤晓鸥教授和
  • Three.js3D可视化介绍,以及本地搭建three.js官网

    一 什么是Three js three js官网 https threejs org Three js是一个基于WebGL的JavaScript 3D图形库 它可以轻松地在浏览器中创建3D场景和动画 同时 它支持外部模型和纹理的导入 让开发
  • Windows Server2012R2 VisualSVN4.2.2-Server在线修改密码搭建

    最近有个3 0 0的svn环境要升级可以web界面自助修改密码的 为了找到这个解决方案 我搜索了很多文章与资料 有不少文章提供的总是各种很隐约 好像它要藏着啥好东西似的 我觉得既然你选择了分享你的成果 那就应该把整个过程整理顺畅 而不是在文

随机推荐

  • python解决数组奇数和偶数位置排序问题

    题目描述 输入一个整数数组 实现一个函数来调整该数组中数字的顺序 使得所有的奇数位于数组的前半部分 所有的偶数位于数组的后半部分 并保证奇数和奇数 偶数和偶数之间的相对位置不变 题目解析 这个题目很简单 只需要判断数组中的元素是奇数还是偶数
  • 生成随机数函数:rand和srand

    头文件为 stdlib h rand 会随机生成一个位于 0 RAND MAX 之间的整数 RAND MAX 是
  • [算法] 深搜整理

    深搜 之前在leetcode上刷题一直都对这个知识点比较模糊 最近 集中写了几道深搜的题目 将自己的思路和题目做了整理写下此篇博客 博客很多题目是网上提供的一些深搜题目 另外一些是leetcode上关于深搜的题目 六角填数 如下图所示六角形
  • 转 C#中的委托和事件 - Part.1

    http www tracefact net tech 009 html C 中的委托和事件 Part 1 2007 9 23 作者 张子阳 分类 C 语言 注意 文中代码在VS2005下通过 由于VS2003 Net Framework
  • jquery mobile实现拨打电话功能

    在做一个便民服务电话 用到移动web中列出的电话 点击需要实现调用通讯录 拨打电话功能 如果需要在移动浏览器中实现拨打电话 发送email 调用sns等功能 jquery mobile提供的接口是一个好办法 采用url链接的方式 实现在Sa
  • mipi-CSI2驱动接口调试 LCD 的CLK时钟频率与显示分辨率及帧率的关系

    锋影 email 174176320 qq com 我们先来看一个公式 Mipiclock width hsync hfp hbp x height vsync vfp vbp x bus width x fps lane num 2 即m
  • 让Unity中的多个模型共用同一个材质球

    如何让Unity中的多个模型共用同一个材质球呢 下面我就来分享一下我之前在做模型的时候所使用的方法和思路 供大家学习 Unity文档中曾明确提到 尽可能的共用Material 这主要是因为渲染引擎一般会按照材质对需要渲染的对象进行排序 同一
  • SCJP认证试题(十三)

    1public class A 2 private int counter 0 3 4 public static int getInstanceCount 5 return counter 6 7 8 public A 9 counter
  • 令牌桶 客户端请求_使用刷新的令牌和cookie进行安全的客户端身份验证

    令牌桶 客户端请求 To start off this is my first article here I ve thought about writing it for a while now Ever since we planned
  • vue3.0 生命周期简介

    setup 替代 beforecreate gt use setup created gt use setup 前面加on beforeMount gt onBeforeMount mounted gt onMounted beforeUp
  • MySQL之2003错误的解决方法

    今天装了MySQL 结果发现到了晚上打开Command Line Client是已输入密码就错误 然后出现一个error2003瞬间窗口关闭 后来找了一下发现是没有开启MySQL server的原因 解决方法 在命令行输入net start
  • OpenStack的部署(六)------Neutron项目

    目录 一 CT控制节点 1 创建数据库neutron 并进行授权 2 创建用户 服务并赋权 3 注册API 4 安装提供者网络 桥接 并修改相关配置文件 5 重启相关服务 二 C1 C2计算节点操作 1 部署neutron服务 2 配置Li
  • ssh安全登录

    ssh远程登录安全协议 1 ssh keygen 一直按回车即可 2 cd home hadoop ssh 验证公钥和私钥是否生成 注意 服务器想免密登录自己也需要配置免密登录 如果执行ssh copy id hostname报命令不存在那
  • 重写QTabWidget,在标签后面添加图标按钮

    原本的QTabWidget没有支持在标签后面添加自定义的按钮的方法 想在后面添加自定义的功能按钮需要重写QTabWidget类 自己实现按钮图标的重绘和鼠标点击判断等操作 1 使用到的主要事件函数 1 void paintEvent QPa
  • scrollview嵌套recyclerview滑动冲突

    给recyclerview设置下面这个属性就行了 recycler setNestedScrollingEnabled false
  • Guns入门

    一 下载源码包 下载地址 https gitee com stylefeng guns 先将项目的guns admin sql下的SQL文件导入到数据库中 主要数据表
  • Java中常见的运行时异常

    ArithmeticException 算数运算异常 由于除数为0引起的异常 ClassCast Exception 类型转换异常 当把一个对象归为某个类 但实际上此对象并不是由这个类创建的 也不是其子类创建的 则会引起异常 ArraySt
  • Ethernet_II帧和802.3_Ethernet帧格式比较

    一 Ethernet帧格式的发展 1980 DEC Intel Xerox制订了Ethernet I的标准 1982 DEC Intel Xerox又制订了Ehternet II的标准 1982 IEEE开始研究Ethernet的国际标准8
  • 【Linux】linux进程间通信netlink socket(用户与内核通信) 二

    目录 1 netlink socket介绍 2 netlink socket特点 3 为什么引入generic netlink 4 netlink通信架构 5 相关结构体 5 1 genl family 5 2 genl ops 5 3 n
  • 如何快速合并两个有序数组?

    前言 大家好 我是来自于 华为 的 程序员小熊 今天给大家带来一道与 数组 相关的题目 这道题同时也是字节 微软和亚马逊等互联网大厂的面试题 即力扣上的第 88 题 合并两个有序数组 本文主要介绍 逆向双指针 的策略来解答此题 供大家参考