leetcode4. 寻找两个正序数组的中位数python_二分查找和递归(困难)

news2024/11/25 20:45:37

题目

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 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

提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

思路和代码

看到这题,先拼接,再sort,根据长度的奇偶返回中间数或中间两个数的平均,一提交,通过。啊,这题也不难啊。

不对,sort的时间复杂度是O(nlogn),不满足题目要求。

题解太难,看了好多天(真的很难看下去啊),有点理解,但不多。有两种方法,一种是二分查找,时间复杂度是O(log (min(m,n)))(哎呀,这个太优秀了,题目要求是O(log (m+n)) ) 。另一种方法就是递归,时间复杂度刚好是题目要求的O(log (m+n)) 。

先看太优秀的二分查找在这题怎么用。

1.二分查找

要来一条线,把num1和nums2分成左边一部分和右边一部分。
在这里插入图片描述
我这个图画的真的太丑也太形象了。

这条线需要满足什么条件?

1.线左边的元素个数和右边的元素个数差不多,如果两个数组总长度是偶数就两边各半,如果是奇数,左边就多分一个。

2.左边元素的值都小于等于右边元素的值。更具体的,因为对于各自数组来说,左边的必定小于右边的,所以这里需要满足交叉小于等于条件,即nums1[i-1] <= nums2[j] and nums2[j-1] <=nums1[i]。这里的i表示nums1数组位置i前面有i个元素,同理j表示nums2数组位置j前面有j个元素。

怎么利用二分查找去找到这条线?

不必在两个数组都找这条分割线,因为左边的元素个数是知道的,当确定第一个数组的分割线位置,推导一下就可以得到第二个数组的分割线位置。

更具体的,设totalleft为左边分得的元素个数。如果m+n是奇数,左边分的(m+n+1)//2个元素,如果m+n是偶数,左边有(m+n)//2个元素,又因为//是向下取整,当m+n是偶数,(m+n)//2 和 (m+n+1)//2是相等的。故不论奇偶,都可以用totalleft = (m+n+1)//2来表示。

当数组nums1的分割线是i时,分割线左边有i个元素。nums1分割线左边的值是nums1[i-1],右边的值就是nums1[i]。而此时,数组nums2的分割线j = totalleft - i。nums2分割线左边的值是nums2[j-1],右边的值就是nums2[j]。

接下来,我们在较短的数组nums1(开始不是nums1的话,nums1和nums2交换一下)利用二分查找找到合适的分割线。注意,查找范围是[0,m] (左闭右闭,因为分割线可能在num1的最右边)。所以初始时left=0,right=m(而不是right=m-1)

我们要找到满足条件nums1[i-1] <= nums2[j] and nums2[j-1] <=nums1[i]的分割线,对该条件取反,只要其中一个一条不满足即可。

i是中间的数,即i=left+(right-left)//2。我们判断nums1[i-1] > nums2[j],说明线画的靠右了,要往左边找,故right = i-1,否则left=i。

注意,当数组只有两个数的时候[left,right],i=left陷入死循环,所以开始求中间位置的时候写成i=left+(right-left+1)//2 。(高,实在是高,我自己肯定想不出来啊,其实懂都没有太懂,反正这样写就可以避免死循环。)

最后跳出循环,更新一下分割线,i=left,j=totalleft-i 。

这就结束了么?并不是!还有一些特殊情况需要处理。例如下图:
在这里插入图片描述
i和j如果为边界值就会报错,所以当 i=0 的时候,分割线在nums1的最左边。左边求最大值,将nums1的分割线左边值设置为负无穷,同理,j=0时,将nums2的分割线左边值设置为负无穷。而当i = m的时候,分割线在nums1的最右边,右边是求最小值,将nums1分割线右边的值设置为正无穷,同理,j=n的时候,将nums2分割线右边的值设置为正无穷。

最后总长度是奇数返回左边最大值,是偶数返回左边最大值和右边最小值的平均值。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        m, n = len(nums1), len(nums2)
        left, right = 0, m
        totalleft = (m + n + 1) // 2
        while left < right:
            i = left + (right - left + 1)//2
            j = totalleft - i
            if nums1[i-1] > nums2[j]:
                right = i-1
            else:
                left = i
        i = left
        j = totalleft - i
        left1 = float("-inf") if i == 0 else nums1[i-1]
        right1 = float("inf") if i == m else nums1[i]
        left2 = float("-inf") if j == 0 else nums2[j-1]
        right2 = float("inf") if j == n else nums2[j]
        return max(left1,left2) if (m+n)%2 else (max(left1,left2)+min(right1,right2))/2

二分查找的时间复杂度是O(log(min(m,n)))。

2.递归

在两个数组中找第k小的数,比较nums1[k//2]和nums2[k//2],如果nums1[k//2] > nums2[k//2],说明nums2的前k//2中的数都不可能是答案,直接舍去。然后不断舍去一些肯定不是答案的值,直到得到最终结果。大概的思路就是这样。

再说一些细节。

递归三要素,参数,终止条件和单层递归逻辑。

首先参数是两个数组,各自的起始位置,和要求的第k个小的数。
findmin(self,nums1,start1,end1, nums2, start2, end2, k)。

终止条件:

其中两个数组的长度len1,len2分别是end1-start1+1,end2-start2+1。

1.当较短的数组长度为0时,直接返回较长数组的第k小的数。
2.当k为1的时候,取两个数组首位元素的较小值。

单层递归逻辑,为了防止越界,nums1的第k小的数位置为i = start1 + min(len1,k//2)-1,j = start2 +min(len2,k//2)-1

当nums1[i] > nums2[j],舍去nums2的前部分,nums2的起始位置变成了j+1,要求得的第k小的数,变成了求第k-(j-start2)-1小的数。否则,舍去nums1前面的部分,nums1的起始位置变成了i+1,要求得的第k小的数,变成了求第k-(i-start2)-1小的数。

代码:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        m, n = len(nums1), len(nums2)
        left = (m+n+1)//2
        right = (m+n+2)//2
        return (self.findkmin(nums1,0,m-1,nums2,0,n-1,left) + self.findkmin(nums1,0,m-1,nums2,0,n-1,right))/2

    def findkmin(self,nums1,start1,end1,nums2,start2,end2,k):
        len1, len2 = end1 - start1 + 1, end2 - start2 + 1
        if len1 > len2:
            return self.findkmin(nums2,start2,end2,nums1,start1,end1,k)
        if len1 == 0:
            return nums2[start2 + k-1]
        if k == 1:
            return min(nums1[start1],nums2[start2])
        i = start1 + min(k//2,len1) -1
        j = start2 + min(k//2,len2) -1
        if nums1[i] > nums2[j]:
            return self.findkmin(nums1,start1,end1,nums2,j+1,end2,k-(j-start2)-1)
        else:
            return self.findkmin(nums1,i+1,end1,nums2,start2,end2,k-(i-start1)-1)

时间复杂度是O(log(m+n))。

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

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

相关文章

第二证券|疫情扰动叠加需求不足,11月制造业PMI回落至48%

国家统计局周三称&#xff0c;11月&#xff0c;受国内疫情点多面广频发&#xff0c;世界环境更趋复杂严峻等多重要素影响&#xff0c;我国制造业收购经理人指数&#xff08;PMI&#xff09;较上月回落1.2个百分点至48.0%。制造业PMI接连两个月低于临界点&#xff0c;制造业下行…

第4季2:并口、MIPI、LVDS的简介

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、并口的简介 1、并口的含义 并口的含义&#xff0c;可以从AR0130或OV9712的原理图中形象地理解。 如下图所示&#xff0c;AR0130采用12bit的并口向SoC传输图像数据信息&#xff0c;而SoC和AR0130…

b站黑马JavaScript的Ajax案例代码——评论列表案例

目标效果&#xff1a; 1.在表单界面输入评论人和内容&#xff0c;点击发表评论按钮&#xff0c;可以在页面下面看到自己刚刚输入的内容 2.发表评论成功之后&#xff0c;用DOM对象的reset方法&#xff1a;重置表单为其默认值 e.g.1初始状态&#xff1a;【下面的评论内容会因为…

STC 51单片机48——数码管显示外部中断次数

#include<reg52.h> #include<intrins.h> #include "math.h" #define uchar unsigned char #define uint unsigned int #define ulong unsigned long //共阴字形码表【实验】数码管实验时&#xff0c;一定要将点阵模块跳针放到VCC上&#xff01;&…

【C语言】哈夫曼树,再来一次解剖

博主&#xff1a;&#x1f44d;不许代码码上红 欢迎&#xff1a;&#x1f40b;点赞、收藏、关注、评论。 格言&#xff1a; 大鹏一日同风起&#xff0c;扶摇直上九万里。 文章目录一、定义结构1.1 定义结点权值的数据类型1.2 定义单个结点信息1.3 字符指针数组中存储的元素类…

C++ Reference: Standard C++ Library reference: Containers: list: list: list

C官网参考链接&#xff1a;https://cplusplus.com/reference/list/list/list/ 公有成员函数 <list> std::list::list C98 默认构造函数 (1) explicit list (const allocator_type& alloc allocator_type()); 填充构造函数 (2) explicit list (size_type n,…

将整个网站变为黑白色

目录 效果&#xff1a; 代码&#xff1a; 兼容性写法&#xff1a; 原理&#xff1a; 效果&#xff1a; ps&#xff1a;实测淘宝也是用的这种方式&#xff0c;有兴趣可以去看看 代码&#xff1a; 使用方式就是找到根标签&#xff0c;将里面的两行代码放进去即可 html {filte…

手写Redux(二):实现React-redux

在React中&#xff0c;组件和组件之间通过props传递数据的规范&#xff0c;极大地增强了组件之间的耦合性&#xff0c;而context类似全局变量一样&#xff0c;里面的数据能被随意接触就能被随意修改&#xff0c;每个组件都能够改context里面的内容会导致程序的运行不可预料。 …

借助cubeMX实现STM32MP157A(-M4核)UART、按键中断、环境检测开关实验

main.c 可以添加一句打印提示 int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init(…

准备蓝桥杯的宝贝们,二分法基础篇(下)例题讲解

二分法例题第一题&#xff1a;搜索插入位置解法一&#xff08;左闭右闭&#xff09;解法二&#xff08;左闭右开&#xff09;解法三&#xff08;暴力求解&#xff09;第二题&#xff1a;在排序数组中查找元素的第一个和最后一个位置解法一&#xff08;左闭右闭&#xff09;第三…

​Base64编码知识详解 ​

在我们进行前端开发时&#xff0c;针对项目优化&#xff0c;常会提到一条&#xff1a;针对较小图片&#xff0c;合理使用Base64字符串替换内嵌&#xff0c;可以减少页面http请求。 并且还会特别强调下&#xff0c;必须是小图片&#xff0c;大小不要超过多少KB&#xff0c;等等。…

Flume监听多个文件目录,并根据文件名称不同,输出到kafka不同topic中

一、Flume监听多个文件目录 1. flume的环境搭建和基础配置参考 https://blog.csdn.net/qinqinde123/article/details/128130131 2. 修改配置文件flume-conf.properties #定义两个是数据源source1、source2 agent.sources source1 source2 agent.channels channel1 agent.…

B. Password(KMP)

Problem - 126B - Codeforces Asterix、Obelix和他们的临时伙伴Suffix和Prefix终于找到了和谐寺。然而&#xff0c;它的门被牢牢地锁住了&#xff0c;即使是Obelix也没能打开它们。 过了一会儿&#xff0c;他们发现在寺庙大门下面的一块岩石上刻着一个字符串。亚力认为那是打开…

realme手机配什么蓝牙耳机?realme蓝牙耳机推荐

蓝牙耳机作为人手必备的单品&#xff0c;不同厂商的产品更是多种多样&#xff0c;用户可以有更多的选择&#xff0c;选购蓝牙耳机的时候&#xff0c;除了看重佩戴舒适度、发声单元人们更加追求最新研发的技术。realme是为年轻人而来的科技潮牌。秉持“敢越级”品牌理念&#xf…

iOS MD5基础知识

MD5信息摘要算法&#xff08;英语&#xff1a;MD5 Message-Digest Algorithm&#xff09;&#xff0c;一种被广泛使用的密码散列函数&#xff0c;可以产生出一个128位&#xff08;16字节&#xff09;的散列值&#xff08;hash value&#xff09;&#xff0c;用于确保信息传输完…

实现了Spring的Aware接口的自定义类什么时候执行的?

在之前的内容中 Spring的Aware接口有什么用&#xff1f;_轻尘的博客-CSDN博客_aware接口的作用 了解到用户可以通过实现相应的Aware接口来获取spring框架提供的能力&#xff0c;俗称“攀亲戚” 以如下代码为例&#xff0c;自定义类MyAware实现了BeanFactroryAware&#xff0…

数据库、计算机网络,操作系统刷题笔记5

数据库、计算机网络&#xff0c;操作系统刷题笔记5 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&…

【MySQL基础】MySQL常用的图形化管理工具有那些?

目录 一、为什么要使用MySQL图形化管理工具 原因 / 目的 / 作用 二、什么是DOS窗口? 三、常见的MySQL图形化管理工具有那些&#xff1f; 四、 常见几个MySQL图形工具的介绍 Navicat SQLyog MySQL Workbench DataGrip 五、Navicat图形工具的安装与使用 第一步&#x…

python带你制作随机点名系统,超级简单

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 在某些难以抉择得时候&#xff0c;我们经常要用外力来帮助我们做出选择 比如&#xff0c;课堂随机点名或面对活动需要人上台表演时等等场景 这个时候&#xff0c;有一个随机点名系统就非常好啦&#xff0c;毕竟运气得事~ …

QT之 给控件添加右键菜单

一、效果预览 二、代码 cpp文件 //listView右键菜单 void MainWindow::Rightclicklistview() {//初始化一级菜单TotalRightclick new QMenu(this);AddDevice new QMenu(this);upDevice new QAction(this);DownDevice new QAction(this);Delete new QAction(this);EditDev…