LeetCode【0004】寻找两个正序数组的中位数

本文目录

  • 1 中文题目
  • 2 求解思路
    • 2.1 基础解法:合并排序法
    • 2.2 优化解法:双指针
    • 2.3 最优解法:二分查找
  • 3 题目总结

1 中文题目

给定两个大小分别为 m m m n n n 的正序(从小到大)数组 n u m s 1 nums1 nums1 n u m s 2 nums2 nums2。请你找出并返回这两个正序数组的中位数 。并且算法的时间复杂度应该为 O ( l o g ( m + n ) ) O(log (m+n)) O(log(m+n))

示例 1:

  • 输入: n u m s 1 = [ 1 , 3 ] , n u m s 2 = [ 2 ] nums1 = [1,3], nums2 = [2] nums1=[1,3],nums2=[2]
  • 输出: 2.00000 2.00000 2.00000
  • 解释:合并数组 = [ 1 , 2 , 3 ] [1,2,3] [1,2,3] ,中位数 2 2 2

示例 2:

  • 输入: n u m s 1 = [ 1 , 2 ] , n u m s 2 = [ 3 , 4 ] nums1 = [1,2], nums2 = [3,4] nums1=[1,2],nums2=[3,4]
  • 输出: 2.50000 2.50000 2.50000
  • 解释:合并数组 = [ 1 , 2 , 3 , 4 ] [1,2,3,4] [1,2,3,4] ,中位数 ( 2 + 3 ) / 2 = 2.5 (2 + 3) / 2 = 2.5 (2+3)/2=2.5

提示:

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

2 求解思路

2.1 基础解法:合并排序法

思路
将两个有序数组合并成一个有序数组,根据合并后数组的长度判断中位数位置,计算并返回中位数

a. 初始化阶段

  • 创建空数组 m e r g e d merged merged用于存储合并结果
  • 初始化两个指针 i i i j j j分别指向 n u m s 1 nums1 nums1 n u m s 2 nums2 nums2的起始位置

b. 合并阶段

  • 比较 n u m s 1 [ i ] nums1[i] nums1[i] n u m s 2 [ j ] nums2[j] nums2[j]的大小
  • 将较小的元素加入 m e r g e d merged merged数组
  • 移动对应的指针
  • 重复直到某个数组遍历完成

c. 处理剩余元素

  • 将未遍历完的数组剩余元素直接加入 m e r g e d merged merged

d. 计算中位数

  • 判断总长度的奇偶性
  • 偶数长度:返回中间两个数的平均值
  • 奇数长度:返回中间的数

Python代码

class Solution:def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:"""寻找两个正序数组的中位数参数:nums1: 第一个有序数组nums2: 第二个有序数组返回:float: 两个数组合并后的中位数"""# 用于存储合并后的有序数组merged = []# 初始化两个数组的指针i, j = 0, 0m, n = len(nums1), len(nums2)# 同时遍历两个数组,比较并合并while i < m and j < n:if nums1[i] <= nums2[j]:# nums1中的元素更小,将其加入mergedmerged.append(nums1[i])i += 1else:# nums2中的元素更小,将其加入mergedmerged.append(nums2[j])j += 1# 处理剩余元素# 如果nums1还有剩余元素while i < m:merged.append(nums1[i])i += 1# 如果nums2还有剩余元素while j < n:merged.append(nums2[j])j += 1# 计算合并后数组的总长度total_length = m + n# 判断总长度的奇偶性并计算中位数if total_length % 2 == 0:# 偶数长度:取中间两个数的平均值return (merged[total_length//2-1] + merged[total_length//2]) / 2else:# 奇数长度:直接返回中间的数return merged[total_length//2]

时空复杂度分析

  • 时间复杂度: 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 ( m + n ) O(m + n) O(m+n)

2.2 优化解法:双指针

思路
不需要真正合并数组,只需遍历到中位数位置,使用两个指针交替前进,维护当前值和前一个值

a. 初始化

  • 计算总长度和需要遍历的次数
  • 设置双指针指向两个数组起始位置

b. 遍历过程

  • 比较两个指针指向的值
  • 选择较小值前进
  • 处理数组遍历完的边界情况

c. 结果计算

  • 奇数长度:返回当前值
  • 偶数长度:计算中间两个数的平均值

python代码

class Solution:def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:"""使用双指针法查找两个有序数组的中位数算法思路:1. 使用两个指针分别遍历两个数组2. 按顺序合并两个数组的元素,直到达到中位数位置3. 根据总长度的奇偶性返回中位数参数:nums1: 第一个有序数组nums2: 第二个有序数组返回:float: 两个数组合并后的中位数"""# 获取两个数组的长度m, n = len(nums1), len(nums2)total_length = m + n# 计算需要遍历的次数# 如果总长度为奇数,需要遍历到中间位置# 如果总长度为偶数,需要遍历到中间两个数k = (total_length + 1) // 2# 定义双指针,分别指向两个数组的起始位置p1 = p2 = 0# 记录当前值和前一个值# 用于计算偶数长度时的平均值current = previous = 0# 遍历直到达到中位数位置for _ in range(k):# 保存前一个值previous = current# 处理边界情况和比较大小if p1 == m:  # nums1已经遍历完current = nums2[p2]p2 += 1elif p2 == n:  # nums2已经遍历完current = nums1[p1]p1 += 1elif nums1[p1] <= nums2[p2]:  # nums1当前值更小current = nums1[p1]p1 += 1else:  # nums2当前值更小current = nums2[p2]p2 += 1# 根据总长度的奇偶性返回结果if total_length % 2 == 1:# 奇数长度:直接返回中间值return currentelse:# 偶数长度:返回中间两个数的平均值# 如果当前遍历次数不够,需要再取一个数if p1 == m:  # nums1已经遍历完next_value = nums2[p2]elif p2 == n:  # nums2已经遍历完next_value = nums1[p1]else:  # 比较两个数组当前值next_value = min(nums1[p1], nums2[p2])return (current + next_value) / 2

时空复杂度分析

  • 时间复杂度: O ( m + n ) O(m+n) O(m+n)
    • 最多遍历到中位数位置: ( m + n ) / 2 (m+n)/2 (m+n)/2
    • 每次遍历常数操作
    • 双指针移动次数: O ( ( m + n ) / 2 ) O((m+n)/2) O((m+n)/2)
  • 空间复杂度: O ( 1 ) O(1) O(1)
    • 双指针:2个整数
    • 当前值和前一个值:2个整数
    • 其他临时变量:常数个
    • 不需要额外数组

2.3 最优解法:二分查找

思路

  • 分割点:将两个数组各自分成左右两部分
  • 平衡条件:左半部分长度等于右半部分(或多1)
  • 正确性条件:左半部分最大值 ≤ 右半部分最小值

查找过程:
(1)在较短数组中二分查找分割点
(2)根据总长度确定另一个数组的分割点
(3)判断分割是否满足条件
(4)调整分割点位置直到找到答案

python代码

class Solution:def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:"""使用分治法查找两个有序数组的中位数核心思想:1. 将数组分成左右两部分,使得左部分的长度等于右部分2. 保证左部分的最大值小于等于右部分的最小值3. 通过二分查找确定分割点参数:nums1: 第一个有序数组nums2: 第二个有序数组返回:float: 两个数组合并后的中位数"""# 确保 nums1 是较短的数组,优化查找过程if len(nums1) > len(nums2):nums1, nums2 = nums2, nums1m, n = len(nums1), len(nums2)# 特殊情况处理:空数组if m == 0:if n % 2 == 0:return (nums2[n//2 - 1] + nums2[n//2]) / 2return nums2[n//2]# 初始化二分查找的范围# left和right表示nums1可能的分割位置left, right = 0, mwhile left <= right:# 在nums1中找分割点i = (left + right) // 2# nums2的分割点由nums1的分割点决定# 确保左右两部分长度相等或左部分多一个j = (m + n + 1) // 2 - i# 获取分割点左右的值# 使用无穷大和无穷小处理边界情况nums1_left = float('-inf') if i == 0 else nums1[i-1]nums1_right = float('inf') if i == m else nums1[i]nums2_left = float('-inf') if j == 0 else nums2[j-1]nums2_right = float('inf') if j == n else nums2[j]# 判断分割是否合适if nums1_left <= nums2_right and nums2_left <= nums1_right:# 找到合适的分割点# 根据总长度的奇偶性返回结果if (m + n) % 2 == 0:# 偶数个元素:返回左半部分最大值和右半部分最小值的平均值left_max = max(nums1_left, nums2_left)right_min = min(nums1_right, nums2_right)return (left_max + right_min) / 2else:# 奇数个元素:返回左半部分的最大值return max(nums1_left, nums2_left)elif nums1_left > nums2_right:# nums1的分割点太靠右,需要向左移动right = i - 1else:# nums1的分割点太靠左,需要向右移动left = i + 1

时空复杂度分析

  • 时间复杂度分析: O ( l o g ( m i n ( m , n ) ) ) O(log(min(m,n))) O(log(min(m,n)))
    二分查找分析:在较短数组中进行二分查找,每次迭代减少一半搜索空间,迭代次数取决于较短数组长度。具体分析:
    • 初始范围: [ 0 , m ] , m [0, m],m [0,m]m为较短数组长度
    • 每次迭代:范围减半
    • 迭代次数: l o g ( m ) log(m) log(m)
    • 每次迭代操作: O ( 1 ) O(1) O(1)
  • 空间复杂度分析: O ( 1 ) O(1) O(1)

3 题目总结

题目难度:困难
数据结构:数组
应用算法:二分查找

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

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

相关文章

使用SearXNG-搭建个人搜索引擎(附国内可用Docker镜像源)

介绍 SearXNG是聚合了七十多种搜索服务的开源搜索工具。我们可以匿名浏览页面&#xff0c;不会被记录和追踪。作为开发者&#xff0c;SearXNG也提供了清晰的API接口以及完整的开发文档。 部署 我们可以很方便地使用Docker和Docker compose部署SearXNG。下面给出Docker部署Se…

【笔记】LLC电路工作频点选择 2-2 开关管与滤波压力

LLC谐振变换器稳态工作波形分析 - 知乎&#xff0c;上面这篇文的结论相较MPS那篇文章的结论更严格。我们分析一下它的频点选择为什么会更窄&#xff1a; 1. LLC电路模型 电流滞后的特性就是电路呈感性注意这里也是开关管ZVS开通。 2.工作循环的波形 iLm的波形&#xff0c;最终…

mysql数据同步到sql server

准备工作 下载安装sql server express 2019 现在安装SSMS(连接数据库GUI) 安装ssms for mysql 需要注意的是在上面的步骤中首先需要根据指导安装mysql ODBC 设置express sa用户密码登录 --change password for login user "sa"Security > Logins > sa (rig…

【SpringMVC】——Cookie和Session机制

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;实践 1&#xff1a;获取URL中的参数 &#xff08;1&#xff09;PathVariable 2&…

B2119 删除单词后缀

B2119 删除单词后缀 #include <iostream> using namespace std; # include <string.h> #include <ctype.h> #include <algorithm> #include <string.h> int main(){ string word; cin>>word; if(word.size()> 2 && word.…

AlohaKit:一组.NET MAUI绘制的开源控件

前言 今天大姚给大家分享一组.NET MAUI绘制的开源、免费&#xff08;MIT License&#xff09;UI控件库&#xff1a;AlohaKit。 MAUI介绍 .NET MAUI是一个开源、免费&#xff08;MIT License&#xff09;的跨平台框架&#xff08;支持Android、iOS、macOS 和 Windows多平台运…

漫谈分布式唯一ID

文章目录 本系列前言UUIDDB自增主键Redis incr命令号段模式雪花算法 本系列 漫谈分布式唯一ID&#xff08;本文&#xff09;分布式唯一ID生成&#xff08;二&#xff09;&#xff1a;leaf分布式唯一ID生成&#xff08;三&#xff09;&#xff1a;uid-generator分布式唯一ID生成…

C语言:文件操作2(又一万字?)

关于文件操作这章内容&#xff0c;因为知道内容较多所以我分两篇发了&#xff0c;但是还是没料到第二篇还是这么多&#xff0c;达到了一万多字&#xff01;&#xff01;&#xff01;作者本人真的将知识点进行了超级详解分析并且举了很多例子来帮助读者理解&#xff0c;本文章较…

STM32标准库-待机模式

1.1 STM32待机模式简介 STM32单片机具有低功耗模式&#xff0c;包括睡眠、停止和待机三种。 运行状态下&#xff0c;HCLK为CPU提供时钟。HCLK由AHB预分频器分频后直接输出得到。 低功耗模式选择需考虑电源消耗、启动时间和唤醒源。 睡眠模式停CPU不停外设时钟&#xff1b; 停止…

C++内存分区

内存分区 C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的 全局区&#xff1a;存放全局变量和静态变量以及常量&#xff08;不包括局部常量&#xff09; 栈区&#xff1a;由编译器自动分配释…

大数据面试题--kafka夺命连环问

1、kafka消息发送的流程&#xff1f; 在消息发送过程中涉及到两个线程&#xff1a;一个是 main 线程和一个 sender 线程。在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给双端队列&#xff0c;sender 线程不断从双端队列 RecordAccumulator 中拉取…

ElasticSearch备考 -- 集群配置常见问题

一、集群开启xpack安全配置后无法启动 在配置文件中增加 xpack.security.enabled: true 后无法启动&#xff0c;日志中提示如下 Transport SSL must be enabled if security is enabled. Please set [xpack.security.transport.ssl.enabled] to [true] or disable security b…

LeetCode:485.最大连续1的个数——简单题简单做

目录 题目——485.最大连续1的个数 题目分析&#xff1a; 图解如下&#xff1a; 代码如下 题目——485.最大连续1的个数 给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,0,1,1,1] 输出&#xff1a;3 解…

如何在Android中自定义property

在Android中创建自定义的属性&#xff08;Android property&#xff09;通常用于调试、性能调优或传递应用和系统之间的信息。 以下是如何在Android中创建和使用自定义属性的步骤&#xff1a; 1. 定义属性 在Android中&#xff0c;属性是以“属性名称属性值”形式定义的键值对…

web——sqliabs靶场——第二关

今天来搞第二关&#xff0c;来看看是什么咸蛋 1.判断是否存在sql注入漏洞 输入1 存在sql注入&#xff0c;报错语句为 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near LIMIT 0,1 …

时序预测 | Python基于CNN-transformer时间序列预测

时序预测 | Python基于CNN-transformer时间序列预测 目录 时序预测 | Python基于CNN-transformer时间序列预测预测效果基本介绍参考资料 预测效果 基本介绍 时序预测 | Python基于CNN-transformer时间序列预测 Cnn-transformer-自适应稀疏自注意力ASSA-对比归一化contranorm预…

windows中docker安装redis和redisinsight记录

创建一个Redis运行容器&#xff0c;命令如下 docker run -it -d --name redis -p 6379:6379 redis --bind 0.0.0.0 --protected-mode no -d 代表Redis容器后台运行 --name redis 给创建好的容器起名叫redis -p 6379:6379 将容器的6379端口映射到宿主机的6379端口&#xff0c;注…

ClickHouse创建账号和连接测试

在之前搭建ClickHouse的时候&#xff0c;把账户相关的去掉了&#xff0c;所以登录和连接的时候是不需要账号密码的&#xff0c;但是实际项目中&#xff0c;肯定是需要根据需要创建账号。 一&#xff0c;创建账号 1&#xff0c;进入到 /etc/clickhouse-server&#xff0c; 编辑…

基于微信小程序实现个人健康管理系统

作者主页&#xff1a;编程千纸鹤 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参…

基于python的天气数据采集与可视化分析,对20个城市的天气适宜出行度分析

摘要 本项目旨在基于Python对20个城市的天气数据进行采集与可视化分析&#xff0c;以评估天气的适宜出行度。该分析通过四个主要指标进行量化&#xff0c;这些指标分别是天气状况良好率、空气质量优良率、气温适宜率和安全天气率。通过这些指标&#xff0c;我们能够有效地判断…