LeetCode_4_困难_寻找两个正序数组的中位数

文章目录

  • 1. 题目
  • 2. 思路及代码实现(Python)
    • 2.1 二分查找
    • 2.2 划分数组


1. 题目

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

算法的时间复杂度应该为 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


提示

  • n u m s 1. l e n g t h = = m nums1.length == m nums1.length==m
  • n u m s 2. l e n g t h = = n nums2.length == n nums2.length==n
  • 0 < = m < = 1000 0 <= m <= 1000 0<=m<=1000
  • 0 < = n < = 1000 0 <= n <= 1000 0<=n<=1000
  • 1 < = m + n < = 2000 1 <= m + n <= 2000 1<=m+n<=2000
  • − 1 0 6 < = n u m s 1 [ i ] , n u m s 2 [ i ] < = 1 0 6 -10^6 <= nums1[i], nums2[i] <= 10^6 106<=nums1[i],nums2[i]<=106

2. 思路及代码实现(Python)

2.1 二分查找

对于查找两个数组的中位数,我们很自然想到中位数的寻找方式,就是将数组由小到大排序,然后根据数组长度,计算出中位数的索引位置,找到相应位置的数即可。现在的问题是,对于拆成两部分的数组,我们如何找到合并后的数组的某个索引位置的值呢?

一个简单的方式是直接把两个数组按顺序合并成一个大数组进行索引,这个过程的时间复杂度为 O ( m + n ) O(m+n) O(m+n),空间复杂度也为 O ( m + n ) O(m+n) O(m+n);由于题目给出的两个数组本身就是有序的,因此还有另一个直观的方法是,对两个数组分别各维护一个指针,共同移动指针的过程判断是否到达中位数的索引位置,该方法的时间复杂度为 O ( m + n ) O(m+n) O(m+n),空间复杂度为 O ( 1 ) O(1) O(1)。然而,题目要求的是让时间复杂度降为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),这相当于就是明示,需要用到二分查找之类的方法。

基于上述的逻辑,我们其实根据索引值就能找到中位数的值,因此二分查找用在如何加快搜索该索引值下的值上,已知有两个数组,长度分别为 m , n m,n m,n,若 m + n m+n m+n 是奇数,则中位数的索引为 ( m + n ) / / 2 (m+n)//2 (m+n)//2,若为偶数,则中位数取索引为 ( m + n ) / / 2 , ( m + n ) / / 2 + 1 (m+n)//2, (m+n)//2+1 (m+n)//2,(m+n)//2+1的两个数的平均值。那如何加速搜索第 k ( k = ( m + n ) / / 2 或 k = ( m + n ) / / 2 + 1 ) k(k=(m+n)//2 或 k=(m+n)//2+1) kk=(m+n)//2k=(m+n)//2+1 个值呢?就需要利用到两个数组也都是有序的这个特点。当我们在已知两数组长度后,计算得到 k k k 值,然后想办法将 k k k 拆开,用以每次比较能排除 k / 2 k/2 k/2 的值,因此,我们需要每次比较两个数组的索引为 k / 2 − 1 k/2-1 k/21 的值,这样,当比较小的值的那方涉及到的 k / 2 k/2 k/2 个值可以被一次排除。存在特殊边界条件,当 k = 1 k=1 k=1,说明要查找的是两个数组中最小的数,取两个数组首元素进行比较即可。

class Solution:def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:def getKthElement(k):index1, index2 = 0, 0while True:# 特殊情况if index1 == m:return nums2[index2 + k - 1]if index2 == n:return nums1[index1 + k - 1]if k == 1:return min(nums1[index1], nums2[index2])# 正常情况newIndex1 = min(index1 + k // 2 - 1, m - 1)newIndex2 = min(index2 + k // 2 - 1, n - 1)pivot1, pivot2 = nums1[newIndex1], nums2[newIndex2]if pivot1 <= pivot2:k -= newIndex1 - index1 + 1index1 = newIndex1 + 1else:k -= newIndex2 - index2 + 1index2 = newIndex2 + 1m, n = len(nums1), len(nums2)totalLength = m + nif totalLength % 2 == 1:return getKthElement((totalLength + 1) // 2)else:return (getKthElement(totalLength // 2) + getKthElement(totalLength // 2 + 1)) / 2

执行用时:44 ms
消耗内存:17.11 MB

参考来源:力扣官方题解

2.2 划分数组

上一个方法通过两个数组的长度计算出中位数的索引,通过维护两个指针来不断更新中位数的索引最终找到中位数。另一个方法是划分数组,我们知道,当 m + n m+n m+n 为偶数时,可以将两个数组的数值划分为长度相等的两部分,其中,数值较小部分的最大值,不大于数值较大部分的最小值;同理,若 m + n m+n m+n 长度为奇数,则较小部分的长度比较大部分长度多1(哪边多1都一样),中位数就是较小部分数组中的最大值。

举个例子: [ 2 , 4 , 5 , 7 , 9 , 11 ] [2,4,5,7,9,11] [2,4,5,7,9,11],在这个数组中,长度为偶数,可以分为 [ 2 , 4 , 5 ] , [ 7 , 9 , 11 ] [2,4,5], [7,9,11] [2,4,5],[7,9,11] 两个数组,而左边数组的最大值,不大于右边数组的最小值。因此,现在题目中有两个数组,假设为 A , B A,B A,B,长度分别为 m , n m,n m,n,则可以通过 0 ≤ i ≤ m 0\leq i\leq m 0im A A A分为两部分 A [ 0 ] , A [ 1 ] , . . . A [ i − 1 ] 和 A [ i ] , . . . , A [ m − 1 ] A[0],A[1],...A[i-1]和A[i],...,A[m-1] A[0],A[1],...A[i1]A[i],...,A[m1],同理,通过 j j j 也可以将 B B B分成两部分 B [ 0 ] , B [ 1 ] , . . . B [ j − 1 ] 和 B [ j ] , . . . , B [ n − 1 ] B[0],B[1],...B[j-1]和B[j],...,B[n-1] B[0],B[1],...B[j1]B[j],...,B[n1],其中,若 m + n m+n m+n 为偶数,则 i + j = ( m + n ) / 2 i+j=(m+n)/2 i+j=(m+n)/2,若为奇数,则 i + j = ( m + n + 1 ) / 2 i+j=(m+n+1)/2 i+j=(m+n+1)/2。因此在已知两个数组长度时,确定了 i i i 的值,即可确定 j j j 的值。(这里有个小坑,就是我们以 i i i 去计算 j j j 的值时,需保证 ( m + n ) / 2 或者 ( m + n + 1 ) / 2 减 i (m+n)/2或者(m+n+1)/2减i (m+n)/2或者(m+n+1)/2i的值要大于等于0,因此需要保证 m ≤ n m\leq n mn,如果 n ≤ m n\leq m nm,则调换一下位置即可)。

关键的地方来了,当我们遍历 A A A 的值时, i i i 递增, j j j 会递减,我们总能找到一个使得 A [ i − 1 ] ≤ B [ j ] A[i-1]\leq B[j] A[i1]B[j]的最大的 i i i,此时,由于 i i i 是临界值,所以 A [ i ] > B [ j ] A[i] \gt B[j] A[i]>B[j],且 B [ j ] ≥ B [ j − 1 ] B[j] \geq B[j-1] B[j]B[j1],所以我们只需搜索 m m m,找到满足 A [ i − 1 ] ≤ B [ j ] A[i-1]\leq B[j] A[i1]B[j] 的最大 i i i 即可,这个搜索过程可以用二分搜索进一步加速。

class Solution:def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:if len(nums1) > len(nums2):return self.findMedianSortedArrays(nums2, nums1)infinty = 2**40m, n = len(nums1), len(nums2)left, right = 0, m# median1:前一部分的最大值# median2:后一部分的最小值median1, median2 = 0, 0while left <= right:# 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]# // 后一部分包含 nums1[i .. m-1] 和 nums2[j .. n-1]i = (left + right) // 2j = (m + n + 1) // 2 - i# nums_im1, nums_i, nums_jm1, nums_j 分别表示 nums1[i-1], nums1[i], nums2[j-1], nums2[j]nums_im1 = (-infinty if i == 0 else nums1[i - 1])nums_i = (infinty if i == m else nums1[i])nums_jm1 = (-infinty if j == 0 else nums2[j - 1])nums_j = (infinty if j == n else nums2[j])if nums_im1 <= nums_j:median1, median2 = max(nums_im1, nums_jm1), min(nums_i, nums_j)left = i + 1else:right = i - 1return (median1 + median2) / 2 if (m + n) % 2 == 0 else median1

执行用时:40 ms
消耗内存:17.14 MB

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

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

相关文章

UCF101 数据集介绍与下载

一、介绍 UCF101 是一个现实动作视频的动作识别数据集&#xff0c;收集自YouTube&#xff0c;提供了来自101个动作类别的13320个视频。官方&#xff1a;https://www.crcv.ucf.edu/research/data-sets/ucf101/ 数据集名称&#xff1a;UCF-101&#xff08;2012&#xff09; 总视…

06、Kafka ------ 各个功能的作用解释(ISR 同步副本、非同步副本、自动创建主题、修改主题、删除主题)

目录 CMAK 各个功能的作用解释★ ISR副本 (同步副本&#xff09;★ 非同步副本★ 自动创建主题★ 修改主题★ 删除主题 CMAK 各个功能的作用解释 ★ ISR副本 (同步副本&#xff09; 简单来说 &#xff0c;ISR 副本 就是 Kafka 认为与 领导者副本 同步的副本。 ISR&#xff0…

双位置继电器DLS-5/2TH 额定电压:110VDC 触点形式:7开3闭 柜内安装

系列型号&#xff1a; DLS-5/1电磁式双位置继电器; DLS-5/2电磁式双位置继电器; DLS-5/3电磁式双位置继电器; DLS-5/2G电磁式双位置继电器; DLS-5/3 220VDC双位置继电器 一、用途 1.1用途 DLS-5双位置继电器(以下简称产品)用于各种保护与自动控制系统中&#xff0c;作为切换…

JPEG格式详解Baseline、Progressive的区别

文章目录 JPEG的简介压缩质量/压缩比率色彩空间基线和渐进子采样存储选项 基线和渐进基线格式渐进格式&#xff1a; 子采样4:4:4&#xff08;无损&#xff09;4:2:24:2:0 JPEG的简介 JPEG&#xff08;Joint Photographic Experts Group&#xff09;是一种常见的图像压缩格式&a…

SpringBoot 配置文件加载优先级

SpringBoot 配置文件加载优先级 前言SpringBoot 配置文件加载优先级 前言 最近在使用k8s部署项目的时候,发现Dockerfile文件中的命令后面跟的参数,无法覆盖nacos中的参数,今天有时间正好来整理一下Springboot配置的加载顺序 SpringBoot 配置文件加载优先级 整理加载顺序第一个肯…

电子学会C/C++编程等级考试2023年12月(一级)真题解析

C/C++编程(1~8级)全部真题・点这里 第1题:数的输入和输出 输入一个整数和双精度浮点数,先将浮点数保留2位小数输出,然后输出整数。 时间限制:1000 内存限制:65536 输入 一行两个数,分别为整数N(不超过整型范围),双精度浮点数F,以一个空格分开。 输出 一行两个数,分…

蓝凌EIS智慧协同平台 ShowUserInfo.aspx SQL注入漏洞复现

0x01 产品简介 蓝凌EIS智慧协同平台是一款专为企业提供高效协同办公和团队合作的产品。该平台集成了各种协同工具和功能,旨在提升企业内部沟通、协作和信息共享的效率。 0x02 漏洞概述 由于蓝凌EIS智慧协同平台 ShowUserInfo.aspx接口处未对用户输入的SQL语句进行过滤或验证…

windows配置电脑网络ip地加的方法

在Windows系统中配置电脑网络IP地址的方法如下&#xff1a; ### 通过图形界面设置 1. **步骤一&#xff1a;打开“网络和互联网设置”** - 点击任务栏右下角的网络图标&#xff08;无线或有线网络图标&#xff09;。 - 在弹出的菜单中选择“网络和共享中心”。 或者&a…

Xcode15 升级问题记录

这里写自定义目录标题 新版本Xcode15升级问题1&#xff1a;rsync error: some files could not be transferred (code 23) at ...参考 新版本Xcode15升级 下载地址&#xff1a;https://developer.apple.com/download/all/ 我目前使用的版本是Xcode15.2 我新创建了一个项目&…

植物大战僵尸小游戏抖音快手直播搭建弹幕插件教程

植物大战弹幕插件功能介绍 该插件由梦歌技术部团队支持开发&#xff0c;本插件软件通过监测抖音弹幕信息&#xff0c;获取礼物数据触发脚本插件对应的功能&#xff1b; 功能目前基本上已经完善&#xff0c;后期功能会陆续上线支持更新&#xff0c;全新的脚本监测稳定方便实用…

文心一言API调用,保姆级案例分享

分享一个调用文心一言API的案例。今天自己用程序去过去文心一言模型中获取结果。 文心一言API调用如何收费&#xff1f; 官方给送了20块钱的体验券&#xff01; 后续收费规则如下 如何开通所需要要的 API key 和 Secret key&#xff1f; api调用需要先在千帆平台开通API key 。…

openGauss学习笔记-193 openGauss 数据库运维-常见故障定位案例-备机卡住-数据库只读

文章目录 openGauss学习笔记-193 openGauss 数据库运维-常见故障定位案例-备机卡住-数据库只读193.1 switchover操作时&#xff0c;主机降备卡住193.1.1 问题现象193.1.2 原因分析193.1.3 处理办法 193.2 磁盘空间达到阈值&#xff0c;数据库只读193.2.1 问题现象193.2.2 原因分…

C语言中的整形提升

整型提升 一、隐式类型转换1.1 整形提升的意义1.2 如何整形提升1.3 练习1.3.1 练习11.3.2 练习2 总结 一、隐式类型转换 C的整型算术运算总是至少以缺省整型类型的精度来进行的。 为了获得这个精度&#xff0c;表达式中的字符和短整型操作数在使用之前被转换为普通整型(int)&a…

数据结构第十二弹---堆的应用

堆的应用 1、堆排序2、TopK问题3、堆的相关习题总结 1、堆排序 要学习堆排序&#xff0c;首先要学习堆的向下调整算法&#xff0c;因为要用堆排序&#xff0c;你首先得建堆&#xff0c;而建堆需要执行多次堆的向下调整算法。 但是&#xff0c;使用向下调整算法需要满足一个前提…

面试算法110:所有路径

题目 一个有向无环图由n个节点&#xff08;标号从0到n-1&#xff0c;n≥2&#xff09;组成&#xff0c;请找出从节点0到节点n-1的所有路径。图用一个数组graph表示&#xff0c;数组的graph[i]包含所有从节点i能直接到达的节点。例如&#xff0c;输入数组graph为[[1&#xff0c…

微信小程序Canvas画布绘制图片、文字、矩形、(椭)圆、直线

获取CanvasRenderingContext2D 对象 .js onReady() {const query = wx.createSelectorQuery()query.select(#myCanvas).fields({ node: true, size: true }).exec((res) => {const canvas = res[0].nodeconst ctx = canvas.getContext(2d)canvas.width = res[0].width * d…

tar命令的常见用法

tar 是一种广泛使用的命令行工具&#xff0c;用于在 Unix 和 Unix-like 系统中创建、维护、提取以及管理 tar 归档文件。以下是 tar 命令的常见用法和选项列表&#xff1a; 基本命令选项 创建归档: -c: 创建一个新的归档文件。例子: tar -cf archive.tar files/ 查看归档内容…

2024--Django平台开发-Web框架和Django基础(二)---Mysql多版本共存(Mac系统)

MySQL多版本共存&#xff08;Mac系统&#xff09; 想要在Mac系统上同时安装【MySQL5.7 】【MySQL8.0】版本&#xff0c;需要进行如下的操作和配置。 想要同时安装两个版本可以采取如下方案&#xff1a; 方案1&#xff1a;【讲解】 MySQL57&#xff0c;用安装包进行安装。 MyS…

遗传算法解决函数最大化问题的完整Python实现

遗传算法&#xff08;Genetic Algorithm&#xff0c;简称GA&#xff09;是一种模拟生物进化过程的启发式优化算法。它通过模拟自然选择、交叉和变异等基因操作&#xff0c;来搜索问题的最优解。 遗传算法的基本思想是通过模拟生物的遗传机制来搜索解空间。算法维护一个种群&am…

每日一篇英语文章分享:I have a dream. 争取早日阅读论文自由.

我有一个梦想》&#xff08;英文&#xff1a;I have a dream&#xff09;是美国黑人民权运动领袖马丁路德金于1963年8月28日在华盛顿林肯纪念堂发表的纪念性演讲。 《我有一个梦想》是马丁路德金在美国黑人受种族歧视和迫害由来已久的背景下&#xff0c;为了推动美国国内黑人争…