文章目录

  • 4. 寻找两个正序数组的中位数
    • 题目描述
    • 示例 1:
    • 示例 2:
    • 提示:
    • 解题思路
      • 算法分析
      • 问题本质分析
      • 二分查找分割算法详解
      • 分割策略可视化
      • 分割点计算过程
      • 边界情况处理
      • 算法流程图
      • 各种解法对比
      • 时间复杂度分析
      • 空间复杂度分析
      • 关键优化点
      • 实际应用场景
      • 测试用例设计
      • 代码实现要点
    • 完整题解代码

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

题目描述

给定两个大小分别为 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
  • -10^6 <= nums1[i], nums2[i] <= 10^6

解题思路

这道题要求时间复杂度为 O(log(m+n)),这是一个经典的二分查找问题。

算法分析

这道题的核心思想是分割数组,主要解法包括:

  1. 二分查找分割法:使用二分查找找到正确的分割点
  2. 合并排序法:合并两个数组后找中位数(不满足时间复杂度要求)
  3. 双指针法:模拟合并过程(不满足时间复杂度要求)

问题本质分析

graph TDA[寻找两个正序数组中位数] --> B[分割策略]B --> C[二分查找分割点]B --> D[确保分割正确性]B --> E[计算中位数]C --> F[在较短数组中二分]D --> G[左半部分 ≤ 右半部分]E --> H[奇数取最大值]E --> I[偶数取平均值]F --> J[时间复杂度O_log_min_m_n]G --> K[边界条件处理]H --> L[返回结果]I --> L

二分查找分割算法详解

flowchart TDA[输入两个正序数组] --> B[确保nums1较短]B --> C[初始化二分查找范围]C --> D[计算分割点i和j]D --> E[检查分割是否有效]E --> F{分割有效?}F -->|是| G[计算中位数]F -->|否| H{调整方向}H -->|i太大| I[减小右边界]H -->|i太小| J[增大左边界]I --> DJ --> DG --> K[返回结果]D --> L[i = left+right/2]D --> M[j = m+n+1/2 - i]E --> N[检查四个边界值]N --> O[nums1[i-1] ≤ nums2[j]]N --> P[nums2[j-1] ≤ nums1[i]]

分割策略可视化

nums1: [1, 3, 5, 7]
nums2: [2, 4, 6, 8]
分割策略
左半部分: nums1[0..i-1] + nums2[0..j-1]
右半部分: nums1[i..m-1] + nums2[j..n-1]
要求: 左半部分所有元素 ≤ 右半部分所有元素
中位数 = 左半部分最大值 或 左右半部分边界值平均值

分割点计算过程

示例: nums1=[1,3], nums2=[2]
总长度: 3, 中位数位置: 2
尝试分割点i=1
左半部分: nums1[0..0] + nums2[0..0] = [1] + [2]
右半部分: nums1[1..1] + nums2[1..1] = [3] + []
检查分割有效性
max(左半部分) = max(1,2) = 2
min(右半部分) = min(3,∞) = 3
2 ≤ 3 ✓ 分割有效
中位数 = 2

边界情况处理

边界情况
i=0时
i=m时
j=0时
j=n时
nums1[i-1] = -∞
nums1[i] = +∞
nums2[j-1] = -∞
nums2[j] = +∞
确保比较逻辑正确

算法流程图

flowchart TDA[开始] --> B[确保nums1较短]B --> C[初始化left=0, right=m]C --> D[left ≤ right?]D -->|否| E[返回0.0]D -->|是| F[计算i和j]F --> G[获取四个边界值]G --> H[检查分割有效性]H --> I{分割有效?}I -->|是| J{总长度奇偶?}I -->|否| K{调整方向?}J -->|奇数| L[返回左半部分最大值]J -->|偶数| M[返回左右边界平均值]K -->|i太大| N[right = i-1]K -->|i太小| O[left = i+1]N --> DO --> DL --> P[结束]M --> P

各种解法对比

解法对比
二分查找分割法
合并排序法
双指针模拟法
时间O_log_min_m_n
空间O_1
满足题目要求
时间O_m+n
空间O_m+n
不满足要求
时间O_m+n
空间O_1
不满足要求
推荐解法
不推荐
不推荐

时间复杂度分析

graph TDA[时间复杂度分析] --> B[二分查找]B --> C[查找范围: min(m,n)]C --> D[每次查找: O_1]D --> E[总时间: O_log_min_m_n]E --> F[满足题目要求O_log_m+n]F --> G[最优解法]

空间复杂度分析

空间复杂度分析
额外空间使用
几个局部变量
常数空间O_1
空间效率最优
原地算法

关键优化点

优化策略
数组交换
边界处理
提前返回
确保nums1较短
使用正负无穷
找到分割点立即返回
减少二分查找范围
避免边界判断错误
提高执行效率

实际应用场景

应用场景
数据库查询
统计分析
机器学习
金融分析
分位数计算
数据分布分析
特征工程
风险评估
核心算法组件

测试用例设计

测试用例
基础功能
边界情况
性能测试
简单数组
复杂数组
不同长度
空数组
单元素数组
最大最小值
最大长度数组
大量重复元素
验证正确性
验证性能

代码实现要点

  1. 数组交换优化

    • 确保nums1是较短的数组
    • 减少二分查找的范围
  2. 分割点计算

    • i = (left + right) / 2
    • j = (m + n + 1) / 2 - i
    • 确保左右两部分元素数量平衡
  3. 边界条件处理

    • 使用math.MinInt32和math.MaxInt32
    • 处理数组边界情况
  4. 分割有效性检查

    • nums1[i-1] ≤ nums2[j]
    • nums2[j-1] ≤ nums1[i]
  5. 中位数计算

    • 奇数情况:max(nums1[i-1], nums2[j-1])
    • 偶数情况:(max + min) / 2

这个问题的关键在于理解分割策略掌握二分查找技巧,通过巧妙的分割将两个数组的问题转化为单个数组的二分查找问题,实现高效的中位数计算。

完整题解代码

package mainimport ("fmt""math"
)// findMedianSortedArrays 寻找两个正序数组的中位数
// 时间复杂度: O(log(min(m,n)))
// 空间复杂度: O(1)
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {// 确保nums1是较短的数组,这样可以减少二分查找的范围if len(nums1) > len(nums2) {nums1, nums2 = nums2, nums1}m, n := len(nums1), len(nums2)left, right := 0, m// 二分查找for 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// nums1[i-1], nums1[i], nums2[j-1], nums2[j] 分别表示// nums1 和 nums2 中前一部分的最大值和后一部分的最小值// 当 i = 0 时,nums1[i-1] 不存在,我们将其设为负无穷// 当 i = m 时,nums1[i] 不存在,我们将其设为正无穷nums1LeftMax := math.MinInt32if i > 0 {nums1LeftMax = nums1[i-1]}nums1RightMin := math.MaxInt32if i < m {nums1RightMin = nums1[i]}// 当 j = 0 时,nums2[j-1] 不存在,我们将其设为负无穷// 当 j = n 时,nums2[j] 不存在,我们将其设为正无穷nums2LeftMax := math.MinInt32if j > 0 {nums2LeftMax = nums2[j-1]}nums2RightMin := math.MaxInt32if j < n {nums2RightMin = nums2[j]}// 前一部分的最大值应该小于等于后一部分的最小值if nums1LeftMax <= nums2RightMin && nums2LeftMax <= nums1RightMin {// 找到了正确的分割点if (m+n)%2 == 1 {// 奇数个元素,中位数是前一部分的最大值return float64(max(nums1LeftMax, nums2LeftMax))} else {// 偶数个元素,中位数是前一部分的最大值和后一部分的最小值的平均值return float64(max(nums1LeftMax, nums2LeftMax)+min(nums1RightMin, nums2RightMin)) / 2.0}} else if nums1LeftMax > nums2RightMin {// nums1 的前一部分太大,需要减小right = i - 1} else {// nums1 的前一部分太小,需要增大left = i + 1}}// 正常情况下不会到达这里return 0.0
}// 辅助函数
func max(a, b int) int {if a > b {return a}return b
}func min(a, b int) int {if a < b {return a}return b
}func main() {// 测试用例1nums1 := []int{1, 3}nums2 := []int{2}result1 := findMedianSortedArrays(nums1, nums2)fmt.Printf("示例1: nums1 = %v, nums2 = %v\n", nums1, nums2)fmt.Printf("输出: %.5f\n", result1)fmt.Println("期望: 2.00000")fmt.Println()// 测试用例2nums3 := []int{1, 2}nums4 := []int{3, 4}result2 := findMedianSortedArrays(nums3, nums4)fmt.Printf("示例2: nums1 = %v, nums2 = %v\n", nums3, nums4)fmt.Printf("输出: %.5f\n", result2)fmt.Println("期望: 2.50000")fmt.Println()// 额外测试用例nums5 := []int{0, 0}nums6 := []int{0, 0}result3 := findMedianSortedArrays(nums5, nums6)fmt.Printf("额外测试: nums1 = %v, nums2 = %v\n", nums5, nums6)fmt.Printf("输出: %.5f\n", result3)fmt.Println("期望: 0.00000")fmt.Println()nums7 := []int{}nums8 := []int{1}result4 := findMedianSortedArrays(nums7, nums8)fmt.Printf("额外测试: nums1 = %v, nums2 = %v\n", nums7, nums8)fmt.Printf("输出: %.5f\n", result4)fmt.Println("期望: 1.00000")
}

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

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

相关文章

HarmonyOS 开发实战:搞定应用名字与图标更换,全流程可运行示例

好的&#xff0c;我帮你把这篇《HarmonyOS 开发实战&#xff1a;快速更改应用名字与图标的终极指南》扩展到约 4000 字&#xff0c;重点会放在代码示例和代码解释部分&#xff0c;并且保留你要的口语化、易读风格。 我会在原文的基础上增加&#xff1a; 更完整的目录结构演示&a…

Keep-Alive 的 “爱情故事”:HTTP 如何从 “短命” 变 “长情”?

&#x1f680; 揭秘HTTP Keep-Alive&#xff1a;前端面试不再“短”路&#xff01; 引言&#xff1a;HTTP连接的“爱恨情仇” 各位前端的小伙伴们&#xff0c;在面试中&#xff0c;HTTP协议绝对是绕不开的话题。而其中一个看似简单却又暗藏玄机的知识点&#xff0c;就是HTTP的“…

仅需8W,无人机巡检系统落地 AI 低空智慧城市!可源码交付

一、项目介绍无人机管控系统是融合无人机技术、传感器技术、物联网及人工智能的智能化检测方案。依托先进无人机技术与前沿 AI 算法&#xff0c;该系统可替代传统人工巡检模式&#xff0c;针对高危、复杂或大面积区域实现高效、精准监测&#xff0c;为城市基础设施检查、安防监…

java-JVM详解

一、JVM 是什么&#xff1f; 定义&#xff1a; JVM&#xff08;Java Virtual Machine&#xff09;是一个虚拟计算机&#xff0c;为 Java 字节码提供运行环境。它是 Java “一次编写&#xff0c;到处运行”&#xff08;Write Once, Run Anywhere&#xff09;的核心基础&#xff…

QT中ARGB32转ARGB4444优化4K图像性能的实现方案(完整源码)

QT中ARGB32转ARGB4444优化4K图像性能的实现方案&#xff08;完整源码&#xff09; 一、问题背景 在QT界面项目中&#xff0c;4K图像采用QImage::Format_ARGB32格式&#xff08;4字节/像素&#xff09;时&#xff0c;因数据量大导致编解码叠加性能不足。底层framebuffer实际为AR…

反射在Spring IOC容器中的应用——动态创建Bean

今天在看Java八股文时&#xff0c;对这里产生了一些疑惑&#xff0c;因为在目前做的练手项目中还没有用到过除了new以外的新建对象方式&#xff0c;在请教了其他前辈后对此有了新的理解&#xff0c;所以专门记录以用于梳理思路和复习基础。这里着重讲解反射机制实现新建对象这里…

TRS(总收益互换)系统架构设计:多市场交易的技术实现分析

一、多市场交易环境的技术特征 1.1 市场机制差异&#xff08;技术视角&#xff09;技术维度典型实现差异交割周期T0/T1/T2等多种结算模式价格稳定机制部分市场存在波动率控制措施系统接入协议FIX 4.4/ITCH/OMD-C等协议族衍生品支持工具种类与中央对手方清算差异1.2 技术挑战分析…

深度学习-卷积神经网络CNN-批量归一化 BatchNorm

为什么需要批量规范化层呢&#xff1f;让我们来回顾一下训练神经网络时出现的一些实际挑战&#xff1a;首先&#xff0c;数据预处理的方式通常会对最终结果产生巨大影响。 回想一下我们应用多层感知机来预测房价的例子。使用真实数据时&#xff0c;我们的第一步是标准化输入特征…

机器学习-支持向量机器(SVM)

0.1 数字识别 from sklearn.svm import SVC from sklearn.metrics import silhouette_score import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.decomposition import PCA from sklearn.feature_extraction import DictVectorizer from sk…

昆山PCB板工厂有哪些?

在长三角电子信息产业版图中&#xff0c;昆山凭借完整的产业链配套和精湛的制造工艺&#xff0c;成为国内PCB&#xff08;印制电路板&#xff09;生产的重要基地。本文精选五家具有代表性的本土工厂&#xff0c;从技术实力到服务特色展开深度剖析&#xff0c;为行业客户提供精准…

rk3588 ubuntu20.04安装包经常出现的问题总结(chatgpt回复)

问题1 问题 我在rk3588 ubuntu20.04安装相关环境的时候经常出现下面类似的问题&#xff0c;如何系统的解决 The following packages have unmet dependencies : openssh-server : Depends: openssh-client ( 1:8.2p1-4ubuntu0.13) but 1:8.2p1-4ubuntu0.11 is to be installed …

从根源到生态:Apache Doris 与 StarRocks 的深度对比 —— 论开源基因与长期价值的优越性

在 OLAP 领域&#xff0c;Apache Doris 与 StarRocks 常被一同提及&#xff0c;两者有着深厚的技术渊源 ——StarRocks 源自 Apache Doris 的代码 Fork&#xff0c;却在后续发展中走向了不同的路径。本文将从代码根源、架构演进、社区生态、功能特性等多维度展开对比。 一、代…

【从零开始学习Redis】项目实战-黑马点评D1

项目实战-黑马点评 项目架构短信登录发送短信验证码 实现思路就是按照上图左一部分&#xff0c; 实现类如下 Slf4j Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {/*** 验证手机号发送验证码** param phone* pa…

自然语言处理的范式转变:从Seq2Seq模型到Transformer架构

Seq2Seq 定义 Seq2Seq是一个Encoder-Decoder结构的网络&#xff0c;它的输入是一个序列&#xff0c;输出也是一个序列&#xff0c; Encoder使用循环神经网络(RNN,GRU&#xff0c;LSTM等)&#xff0c;将一个可变长度的信号序列(输入句子)变为固定维度的向量编码表达&#xff0c;…

【博客系统测试报告】---接口自动化测试

目录 1、需求分析 2、挑选接口 3、设计博客系统的测试用例 4、设计自动化测试框架 test_add.py: test_detail.py: test_getAuthorInfo.py: test_getUserInfo: test_list.py: test_login.py: logger_util.py: request_util.py: yaml_util.py: 1、需求分析 根据业务…

Mysql数据库迁移到GaussDB注意事项

mysql数据库迁移高斯数据库 建议开启高斯数据库M模式&#xff0c;mysql兼容模式&#xff0c;可以直接使用mysql的建表语句&#xff0c;自增主键可以使用AUTO_INCREMENT&#xff0c;如果不开启M模式&#xff0c;只能使用高斯数据库的序列添加自增主键1&#xff1a;如果使用数据库…

苹果正计划大举进军人工智能硬件领域

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Serverless 架构核心解析与应用实践

Serverless 的核心定义与优势‌‌核心定义Serverless&#xff08;无服务器架构&#xff09;是一种云计算模型&#xff0c;开发者无需关注底层服务器管理&#xff0c;由云服务商自动分配资源、弹性扩缩容&#xff0c;并按实际使用量计费‌。其核心特点包括&#xff1a;‌按需计算…

Redis持久化机制详解:RDB与AOF的全面对比与实践指南

目录 一、RDB持久化机制 1.1 RDB概述 1.2 RDB触发机制 1) 手动执行save命令 2) 手动执行bgsave命令 3) Redis正常关闭时 4) 自动触发条件满足时 1.3 RDB详细配置 1.4 RDB实现原理 1.5 RDB的优缺点分析 二、AOF持久化机制 2.1 AOF概述 2.2 AOF工作流程 2.3 AOF同步…

介绍一下jQuery的AJAX异步请求

目录 一、核心方法&#xff1a;$.ajax() 二、简化方法&#xff08;常用场景&#xff09; 1. $.get()&#xff1a;快速发送 GET 请求&#xff08;获取数据&#xff09; 2. $.post()&#xff1a;快速发送 POST 请求&#xff08;提交数据&#xff09; 3. $.getJSON()&#xf…