【力扣高频题】004.两个正序数组的中位数

news2024/10/6 10:39:59

------------------ 长文警告 ------------------

4.两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数

算法的时间复杂度应该为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n))

示例 1:

输入: nums1 = [1,3], nums2 = [2]

输出: 2.00000

解释: 合并数组 = [1,2,3] ,中位数 2 。

示例 2:

输入: nums1 = [1,2], nums2 = [3,4]

输出: 2.50000

解释: 合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5 。

思路分析

本题的暴力思路其实很简单:

  • 由于两个数组是正序的,因此可以采用 双指针 的方式将两个数组合并成为一个新的有序数组,并根据m + n为奇数还是偶数返回其中位数即可
  • 该方法由于使用了双指针的方式,需要遍历整个数组,因此其时间复杂度为 O ( M a x ( m , n ) ) O(Max(m,n)) O(Max(m,n))

但由于本题要求时间复杂度为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),因此需要探究一种更加高效的算法。


接下来我们先来介绍并实现 两个函数 ,进而对本题进行求解。

函数一:

函数功能: 合并两个有序且长度相等的数组,返回其中位数(奇数长度时)或上中位数(偶数长度时)。因此很显然,需要分两种情况进行讨论。

  • 长度为偶数
    • 以数组长度为 4 进行举例说明:


  • 长度为奇数
    • 以数组长度为 5 进行举例说明:

因此,为了能够继续使用该函数进行递归,需要从较长数组中舍弃一个。

舍弃方法是:长数组的最小值与短数组的最大值进行比较 。

函数二:

函数功能: 合并两个有序但不一定等长的数组,返回其第 K 小的数。

下面对以上三种不同的情况进行讨论分析,为方便说明,取n = 3m = 7



与情况 2)推广与证明方法类似,这里不再赘述,感兴趣的小伙伴可以仿照 2)证明一下该方法的正确性。


至此,我们就介绍完了两个函数的功能:

函数一getUpMedian 合并两个有序且长度相等的数组,返回其上中位数。

函数二findKthNum 合并两个有序但不一定等长的数组,返回其第 K 小的数。

实现了这两个函数功能后,本题主函数思路就很容易构思到了:

给定两个任意长度的数组后,

  1. 若两数组长度之和为奇数时,调用findKthNum(size/2+1),求中位数。
  2. 若两数组长度之和为偶数时,调用findKthNum(size/2)findKthNum(size/2+1),再求二者均值,即中位数。
  3. 注意考虑边界条件,若其中一个数组长度为 0 ,直接返回另外一个有序数组的上中位数即可。

函数一代码

public static int getUpMedian(int[] A, int s1, int e1, int[] B, int s2, int e2) {
    int mid1 = 0;
    int mid2 = 0;
    while (s1 < e1) {
        mid1 = (s1 + e1) / 2;
        mid2 = (s2 + e2) / 2;
        if (A[mid1] == B[mid2]) {
            return A[mid1];
        }
        if (((e1 - s1 + 1) & 1) == 1) { // 奇数长度
            if (A[mid1] > B[mid2]) {
                if (B[mid2] >= A[mid1 - 1]) {
                    return B[mid2];
                }
                e1 = mid1 - 1;
                s2 = mid2 + 1;
            } else { // A[mid1] < B[mid2]
                if (A[mid1] >= B[mid2 - 1]) {
                    return A[mid1];
                }
                e2 = mid2 - 1;
                s1 = mid1 + 1;
            }
        } else { // 偶数长度
            if (A[mid1] > B[mid2]) {
                e1 = mid1;
                s2 = mid2 + 1;
            } else {
                e2 = mid2;
                s1 = mid1 + 1;
            }
        }
    }
    return Math.min(A[s1], B[s2]);
}

函数二代码

public static int findKthNum(int[] arr1, int[] arr2, int K) {
    int[] longs = arr1.length >= arr2.length ? arr1 : arr2;
    int[] shorts = arr1.length < arr2.length ? arr1 : arr2;
    int m = longs.length;
    int n = shorts.length;
    if (K <= n) {
        return getUpMedian(shorts, 0, K - 1, longs, 0, K - 1);
    }
    if (K > m) {
        if (shorts[K - m - 1] >= longs[m - 1]) {
            return shorts[K - m - 1];
        }
        if (longs[K - n - 1] >= shorts[n - 1]) {
            return longs[K - n - 1];
        }
        return getUpMedian(shorts, K - m, n - 1, longs, K - n, m - 1);
    }
    if (longs[K - n - 1] >= shorts[n - 1]) {
        return longs[K - n - 1];
    }
    return getUpMedian(shorts, 0, n - 1, longs, K - n, K - 1);
}

主函数

public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n1 = nums1.length;
    int n2 = nums2.length;
    int size = n1 + n2;
    boolean even = (size & 1) == 0;
    if (n1 != 0 && n2 != 0) {
        if (even) {
            return (double) (findKthNum(nums1, nums2, size / 2) + findKthNum(nums1, nums2, size / 2 + 1)) / 2D;
        } else {
            return findKthNum(nums1, nums2, size / 2 + 1);
        }
    } else if (n1 != 0) {
        if (even) {
            return (double) (nums1[(size - 1) / 2] + nums1[size / 2]) / 2;
        } else {
            return nums1[size / 2];
        }
    } else if (n2 != 0) {
        if (even) {
            return (double) (nums2[(size - 1) / 2] + nums2[size / 2]) / 2;
        } else {
            return nums2[size / 2];
        }
    } else {
        return 0;
    }
}

复杂度分析

findKthNum函数和getUpMedian函数,由于采用了递归调用求解第 K 小的数字或上中位数,每次递归根据不同位置,几乎抛弃了一半的一定不可能出现的数组元素。

因此,时间复杂度为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n))

总结

本题的思维量较大,能够认真阅读完的小伙伴很不容易啦 ~

在解决该题的 中位数问题 时,我们顺便解决了如何寻找两个有序但不一定等长的数组中 第 K 小的数 的方法,该方法适用的 范围更广泛 ,能够适当迁移去解决其他问题哦!!!

写在最后

前面的算法文章,更新了许多 专题系列 。包括:滑动窗口、动态规划、加强堆、二叉树递归套路 等。

还没读过的小伙伴可以关注,在主页中点击对应链接查看哦~

接下来的一段时间,将持续 「力扣高频题」 系列文章,想刷 力扣高频题 的小伙伴也可以关注一波哦 ~

~ 点赞 ~ 关注 ~ 星标 ~ 不迷路 ~!!!

回复「ACM紫书」获取 ACM 算法书籍 ~
回复「算法导论」获取 算法导论第3版 ~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1875240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【期末速成】计算机操作系统 EP03 | 学习笔记

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;☀️☀️☀️2.1 考点五&#xff1a;进程的概念及特征2.1 考点六&#xff1a;进程的状态与切换 三、总结&#xff1a;&#x1f353;&#x1f353;&#x1f353; 一、前言&#x1f680;&#x1f6…

Unix/Linux shell实用小程序1:生字本

前言 在日常工作学习中&#xff0c;我们会经常遇到一些不认识的英语单词&#xff0c;于时我们会打开翻译网站或者翻译软件进行查询&#xff0c;但是大部分工具没有生词本的功能&#xff0c;而有生字本的软件又需要注册登陆&#xff0c;免不了很麻烦&#xff0c;而且自己的数据…

linux-内存映射MMAP-lseek-dup-fifo-通信-IO多路复用

1、内存映射MMap&#xff1a; DMA&#xff1a; 可以用*/[]取代read和write&#xff1b; 限制&#xff1a; 1、文件大小固定不能改变&#xff1b;&#xff08;ftruncate&#xff09; 2、只能是磁盘文件&#xff1b; 3、建立映射之前先open mmap函数&#xff1a; mmap第一个…

GAN论文阅读笔记(10)—— High-fidelity GAN Inversion with Padding Space

论文&#xff1a;High-fidelity GAN Inversion with Padding Space paper&#xff1a;136750036.pdf (ecva.net) code&#xff1a;EzioBy/padinv: [ECCV 2022] PadInv: High-fidelity GAN Inversion with Padding Space (github.com) 关键词&#xff1a;GAN, GAN 反演 ( GAN I…

MobPush HarmonyOS NEXT 版本集成指南

开发工具&#xff1a;DevEco Studio 集成方式&#xff1a;在线集成 HarmonyOS API支持&#xff1a;> 11 集成前准备 注册账号 使用MobSDK之前&#xff0c;需要先在MobTech官网注册开发者账号&#xff0c;并获取MobTech提供的AppKey和AppSecret&#xff0c;详情可以点击查…

React实战学习(一)_棋盘设计

需求&#xff1a; 左上侧&#xff1a;状态左下侧&#xff1a;棋盘&#xff0c;保证胜利就结束 和 下过来的不能在下右侧&#xff1a;“时光机”,保证可以回顾&#xff0c;索引 语法&#xff1a; 父子之间属性传递&#xff08;props&#xff09;子父组件传递&#xff08;写法上&…

第十三章 常用类

一、包装类 1. 包装类的分类 &#xff08;1&#xff09;针对八种基本数据类型相应的引用类型—包装类 &#xff08;2&#xff09;有了类的特点&#xff0c;就可以调用类中的方法。 2. 包装类和基本数据的转换 jdk5 前的手动装箱和拆箱方式&#xff0c;装箱&#xff1a;基本…

使用SpringBoot整合filter

SpringBoot整合filter&#xff0c;和整合servlet类似&#xff0c;也有两种玩儿法 1、创建一个SpringBoot工程&#xff0c;在工程中创建一个filter过滤器&#xff0c;然后用注解WebFilter配置拦截的映射 2、启动类还是使用ServletComponentScan注解来扫描拦截器注解WebFilter 另…

通过百度文心智能体创建STM32编程助手-实操

一、前言 文心智能体平台AgentBuilder 是百度推出的基于文心大模型的智能体&#xff08;Agent&#xff09;平台&#xff0c;支持广大开发者根据自身行业领域、应用场景&#xff0c;选取不同类型的开发方式&#xff0c;打造大模型时代的产品能力。开发者可以通过 prompt 编排的…

主从复制、哨兵以及Cluster集群

目录 1.Redis高可用 2.Redis主从复制 2.1 主从复制的作用 2.2 主从复制流程 2.3 搭建Redis主从复制 2.3.1 修改Redis配置文件&#xff08;Master节点操作&#xff09; 2.3.2 修改Redis配置文件&#xff08;Slave节点操作&#xff09; 2.3.2 验证主从复制结果 3.Redis哨…

Oracle新特性速递:未来数据库技术的无限可能

文章目录 一、自治数据库&#xff1a;智能化与自动化的革命二、机器学习集成&#xff1a;智能数据分析的新境界三、区块链技术&#xff1a;确保数据完整性与透明性四、云原生数据库&#xff1a;灵活扩展与快速部署五、人工智能优化器&#xff1a;智能查询执行计划《Oracle从入门…

Pow(x,n)快速冥算法

快速幂算法 快速幂算法是一种通过分治和递归的方式来计算幂运算的方法&#xff0c;其核心思想是利用分治和递归减少乘法的次数来显著提高效率。 基本原理&#xff1a; 给定 x 和 n&#xff0c;计算 x^n 的过程如下&#xff1a; 基本情况处理&#xff1a;如果指数 n 是 0&…

【STM32修改串口波特率】

STM32微控制器中的串口波特率调整通常涉及到USART&#xff08;通用同步接收器/发送器&#xff09;模块的配置。USART模块提供了多个寄存器来设置波特率&#xff0c;其中关键的寄存器包括BRR&#xff08;波特率寄存器&#xff09;和USART_CR1&#xff08;控制寄存器1&#xff09…

【嵌入式操作系统(Linux篇)】实验期末复习(1)

以下是关于嵌入式操作系统&#xff08;Linux篇&#xff09;的实验汇总&#xff0c;大概率都是会考的 特别是shell程序和文件IO的操作 嵌入式操作系统实验小结—涉及期末大题 &#xff08;一&#xff09;Linux操作系统的使用实验 1、认识Linux操作系统的目录结构 请进入自己…

【C++课程设计——演讲比赛系统】

文章目录 前言一、演讲比赛程序需求二、每个功能模块的实现1. 创建管理类(.h文件)2.1. 创建管理类(.cpp文件)3.创建参赛选手类(.h)4.将整体逻辑进行封装 测试项目总结 前言 在学习完C的stl容器后&#xff0c;我们来写一下小项目对其进行应用&#xff01; 项目名称为&#xff1…

cocos creator 调试插件

适用 Cocos Creator 3.4 版本&#xff0c;cocos creator 使用google浏览器调试时&#xff0c;我们可以把事实运行的节点以节点树的形式显示在浏览器上&#xff0c;支持运行时动态调整位置等、、、 将下载的preview-template插件解压后放在工程根目录下&#xff0c;然后重新运行…

day23-- 39. 组合总和+40.组合总和II + 131.分割回文串

一、 39. 组合总和 题目链接&#xff1a;https://leetcode.cn/problems/combination-sum/ 文章讲解&#xff1a;https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1KT4y1M7HJ 1.1 初见思路…

JAVA期末速成库(10)第十一章

一、习题介绍 Check Point&#xff1a;P416 11.1&#xff0c;11.6&#xff0c;11.7&#xff0c;11.8&#xff0c;11.12&#xff0c;11.17&#xff0c;11.24 Programming Exercise&#xff1a;11.1 二、习题及答案 Check Point&#xff1a; 11.1 True or false? A subcl…

Windows下activemq集群配置(broker-network)

1.activemq版本信息 activemq&#xff1a;apache-activemq-5.18.4 2.activemq架构 3.activemq集群配置 activemq集群配置基于Networks of Brokers 这种HA方案的优点&#xff1a;是占用的节点数更少(只需要2个节点),而且2个broker都可以响应消息的接收与发送。不足&#xff…

003-GeoGebra如何无缝嵌入到PPT里

GeoGebra无缝嵌入到PPT里真是一个头疼的问题&#xff0c;已成功解决&#xff0c;这里记录一下&#xff0c;希望可以帮助到更多人。 注意&#xff0c;后续所有的文章说的PPT都是Offce Power Point, 不要拿着WPS的bug来问我哦&#xff0c;我已经戒WPS了&#xff08;此处表示无奈&…