寻找两个正序数组的中位数:分治法与二分查找的结合

寻找两个正序数组的中位数:分治法与二分查找的结合

在算法领域,"寻找两个正序数组的中位数" 是一道经典的高频面试题(LeetCode 第 4 题)。它不仅考察基本的数组操作,还涉及二分查找分治思想的结合。今天,我们就来深入剖析这道题,并用详细代码讲解其高效解法。

1. 题目分析

给定两个大小分别为 mn有序数组 nums1nums2,要求找出它们合并后的中位数 。要求算法的时间复杂度为 O(log(m + n))

1.1 示例

输入

plaintext 复制代码
nums1 = [1, 3]
nums2 = [2]

输出

plaintext 复制代码
2.0

输入

plaintext 复制代码
nums1 = [1, 2]
nums2 = [3, 4]

输出

plaintext 复制代码
2.5

2. 朴素解法:归并再求中位数(O(m + n))

最直观的方法是将两个有序数组合并,然后直接找到中位数。但由于合并过程需要 O(m + n) 时间,不满足 O(log(m + n)) 的要求,所以我们需要更优的方法。

3. 高效解法:二分查找 + 分治思想

我们可以利用二分查找来优化,核心思路如下:

  • nums1nums2 的总长度为 m + n
  • 我们的目标是找到第 (m+n)/2 小的数,而不是直接合并数组。
  • 通过二分查找 ,在 nums1nums2 之间动态调整搜索范围,逐步逼近答案。

4. 代码实现(Python)

python 复制代码
def findMedianSortedArrays(nums1, nums2):
    # 确保 nums1 的长度不大于 nums2
    if len(nums1) > len(nums2):
        nums1, nums2 = nums2, nums1
    
    m, n = len(nums1), len(nums2)
    left, right = 0, m
    median_pos = (m + n + 1) // 2  # 找到中位数的位置
    
    while left <= right:
        partition1 = (left + right) // 2  # 切割 nums1
        partition2 = median_pos - partition1  # 确保左半部分的总元素个数
        
        # 获取切割后的左右元素
        maxLeft1 = float('-inf') if partition1 == 0 else nums1[partition1 - 1]
        minRight1 = float('inf') if partition1 == m else nums1[partition1]
        
        maxLeft2 = float('-inf') if partition2 == 0 else nums2[partition2 - 1]
        minRight2 = float('inf') if partition2 == n else nums2[partition2]
        
        # 检查是否找到合适的划分
        if maxLeft1 <= minRight2 and maxLeft2 <= minRight1:
            # 如果元素总数是奇数,返回左侧最大值
            if (m + n) % 2 == 1:
                return max(maxLeft1, maxLeft2)
            # 否则返回两个中间值的均值
            return (max(maxLeft1, maxLeft2) + min(minRight1, minRight2)) / 2
        
        # 调整二分查找范围
        elif maxLeft1 > minRight2:
            right = partition1 - 1  # 左移
        else:
            left = partition1 + 1  # 右移

5. 代码解析

核心思想

  • 通过二分查找 ,我们试图在 nums1nums2 中找到一个合适的切割,使得两部分满足条件:
    • 左半部分的最大值 ≤ 右半部分的最小值
  • 我们使用 partition1partition2 来划分 nums1nums2
  • 通过调整 partition1 的位置,动态缩小范围,最终找到中位数。

时间复杂度

  • 由于每次搜索都将 nums1 的搜索范围缩小一半,因此时间复杂度为 O(log(min(m, n)))

6. 为什么用二分查找?

这道题的核心是不合并数组,直接找到中位数

  • 由于数组是有序的,我们可以利用二分查找,只关注中位数的位置,而不是整个数组。
  • 通过不断调整 partition1 的位置,我们可以快速确定划分点,而不需要合并数组。

7. 总结

在这篇文章中,我们学习了寻找两个正序数组的中位数的最优解法:

  • 朴素解法 :合并后找中位数(O(m + n))。
  • 二分查找 + 分治法 :不合并数组,直接在 nums1nums2 之间找到合适的划分点(O(log(min(m, n))))。

这道题不仅考察二分查找的应用 ,还涉及分治思想,是典型的高效算法设计题目。希望这篇文章能帮助你理解这道经典算法题,也欢迎交流更优解法!

相关推荐
MicroTech20258 分钟前
MLGO微算法科技通过 Lindbladians 设计线性微分方程的近似最优量子算法——开放量子系统框架下的量子ODE求解新范式
科技·算法·量子计算
知乎的哥廷根数学学派15 分钟前
基于多尺度特征提取和注意力自适应动态路由胶囊网络的工业轴承故障诊断算法(Pytorch)
开发语言·网络·人工智能·pytorch·python·算法·机器学习
源代码•宸17 分钟前
Leetcode—85. 最大矩形【困难】
经验分享·算法·leetcode·职场和发展·golang·单调栈
平哥努力学习ing29 分钟前
《数据结构》-第八章 排序
数据结构·算法·排序算法
CoovallyAIHub29 分钟前
为AI装上“纠偏”思维链,开源框架Robust-R1显著提升多模态大模型抗退化能力
深度学习·算法·计算机视觉
小棠师姐38 分钟前
随机森林原理与实战:如何解决过拟合问题?
算法·机器学习·随机森林算法·python实战·过拟合解决
范纹杉想快点毕业1 小时前
欧几里得算法与扩展欧几里得算法,C语言编程实现(零基础全解析)
运维·c语言·单片机·嵌入式硬件·算法
f***24111 小时前
Bug悬案:技术侦探的破案指南
算法·bug
Swift社区1 小时前
LeetCode 472 连接词
算法·leetcode·职场和发展
Dream it possible!1 小时前
LeetCode 面试经典 150_二分查找_搜索旋转排序数组(114_33_C++_中等)
c++·leetcode·面试