【力扣算法02】之寻找两个正序数组的中位数 - python

简介: 【力扣算法02】之寻找两个正序数组的中位数 - python

问题描述


给定两个大小分别为 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

解题思路


  1. 定义了一个名为Solution的类,它包含了一个名为findMedianSortedArrays的方法,这个方法用于查找两个已排序数组的中位数。
  2. 方法参数包括self(表示方法所属的类实例)、nums1nums2(两个已排序的数组)。
  3. 首先,通过比较两个数组的长度,确保nums1是较短的数组,将较长的数组赋值给nums2,以简化后续操作。
  4. 获取nums1nums2的长度分别赋值给变量mn
  5. 初始化变量leftright,分别表示二分查找的起始左右边界,初始值为0m
  6. 初始化变量median1median2,分别表示中位数的左侧和右侧值,初始值为0
  7. 进入while循环,循环条件为left <= right,即当左边界小于等于右边界时,进行循环。
  8. 在循环中,首先计算出两个数组的当前的分隔点partition1partition2,其中partition1nums1的分隔点,partition2nums2的分隔点。
  9. 根据分隔点,计算出四个值:maxLeft1minRight1maxLeft2minRight2
  • maxLeft1表示nums1左侧最大的值,如果partition1为0,则取float('-inf')表示负无穷大;否则,取nums1[partition1-1]
  • minRight1表示nums1右侧最小的值,如果partition1等于m,则取float('inf')表示正无穷大;否则,取nums1[partition1]
  • maxLeft2表示nums2左侧最大的值,如果partition2为0,则取float('-inf')表示负无穷大;否则,取nums2[partition2-1]
  • minRight2表示nums2右侧最小的值,如果partition2等于n,则取float('inf')表示正无穷大;否则,取nums2[partition2]
  1. 接下来通过比较四个值的大小关系,判断当前的分隔点是否符合中位数的条件:
  • 如果满足条件maxLeft1 <= minRight2maxLeft2 <= minRight1,则说明找到了符合中位数条件的分隔点。
  • 如果(m + n)为偶数,则中位数为(max(maxLeft1, maxLeft2) + min(minRight1, minRight2)) / 2.0
  • 如果(m + n)为奇数,则中位数为max(maxLeft1, maxLeft2)
  • 返回计算得到的中位数。
  1. 如果maxLeft1 > minRight2,说明当前的分隔点在nums1中太靠右,需要将右边界right更新为partition1 - 1
  2. 否则,说明当前的分隔点在nums1中太靠左,需要将左边界left更新为partition1 + 1
  3. 循环结束后,如果没有找到符合条件的分隔点,则抛出ValueError异常,表示输入无效。


代码分析


class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1

这部分代码定义了一个名为Solution的类,并在该类中定义了一个名为findMedianSortedArrays的方法。方法接受两个已排序的数组nums1nums2作为输入。如果nums1的长度大于nums2的长度,则交换两个数组,以确保nums1是较短的数组。

m, n = len(nums1), len(nums2)
        left, right = 0, m
        median1, median2 = 0, 0

这部分代码初始化了一些变量。mn分别表示nums1nums2的长度。leftright分别表示二分查找的起始左右边界,初始值为0mmedian1median2分别表示中位数的左侧和右侧值,初始值为0

while left <= right:
            partition1 = (left + right) // 2
            partition2 = (m + n + 1) // 2 - 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]

这部分代码进入了一个while循环,该循环用于执行二分查找。循环条件是left <= right,即当左边界小于等于右边界时,进行循环。

在循环中,首先计算出两个数组的当前的分隔点partition1partition2partition1nums1的分隔点,partition2nums2的分隔点。

然后,通过分隔点计算出四个值:maxLeft1minRight1maxLeft2minRight2

  • maxLeft1表示nums1左侧最大的值,如果partition1为0,则取float('-inf')表示负无穷大;否则,取nums1[partition1-1]
  • minRight1表示nums1右侧最小的值,如果partition1等于m,则取float('inf')表示正无穷大;否则,取nums1[partition1]
  • maxLeft2表示nums2左侧最大的值,如果partition2为0,则取float('-inf')表示负无穷大;否则,取nums2[partition2-1]
  • minRight2表示nums2右侧最小的值,如果partition2等于n,则取float('inf')表示正无穷大;否则,取nums2[partition2]
if maxLeft1 <= minRight2 and maxLeft2 <= minRight1:
                if (m + n) % 2 == 0:
                    median1 = max(maxLeft1, maxLeft2)
                    median2 = min(minRight1, minRight2)
                    return (median1 + median2) / 2.0
                else:
                    median1 = max(maxLeft1, maxLeft2)
                    return median1
            elif maxLeft1 > minRight2:
                right = partition1 - 1
            else:
                left = partition1 + 1

在循环体中,根据四个值的大小关系判断当前的分隔点是否符合中位数的条件。如果满足条件maxLeft1 <= minRight2maxLeft2 <= minRight1,则说明找到了符合中位数条件的分隔点。

如果(m + n)为偶数,则中位数为(max(maxLeft1, maxLeft2) + min(minRight1, minRight2)) / 2.0

如果(m + n)为奇数,则中位数为max(maxLeft1, maxLeft2)

如果找到了中位数,直接返回中位数。

如果maxLeft1 > minRight2,说明当前的分隔点在nums1中太靠右,需要将右边界right更新为partition1 - 1

否则,说明当前的分隔点在nums1中太靠左,需要将左边界left更新为partition1 + 1

raise ValueError("Invalid input")
• 1

循环结束后,如果没有找到符合条件的分隔点,抛出ValueError异常,表示输入无效。

代码通过二分查找的方式在两个已排序数组中寻找中位数,时间复杂度为O(log(min(m, n))),其中m和n分别为两个数组的长度。


完整代码


class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
            # 如果nums1的长度大于nums2的长度,则交换两个数组,使得nums1成为较短的数组
        m, n = len(nums1), len(nums2)
        left, right = 0, m
        median1, median2 = 0, 0
        # m和n分别表示nums1和nums2的长度,left和right初始化为0和m,median1和median2初始化为0
        while left <= right:
            partition1 = (left + right) // 2
            partition2 = (m + n + 1) // 2 - partition1
            # 计算当前的分割点partition1和partition2
            # 使用二分查找的方法查找中位数
            maxLeft1 = float('-inf') if partition1 == 0 else nums1[partition1 - 1]
            minRight1 = float('inf') if partition1 == m else nums1[partition1]
            # 计算nums1中左侧的最大值和右侧的最小值
            maxLeft2 = float('-inf') if partition2 == 0 else nums2[partition2 - 1]
            minRight2 = float('inf') if partition2 == n else nums2[partition2]
            # 计算nums2中左侧的最大值和右侧的最小值
            if maxLeft1 <= minRight2 and maxLeft2 <= minRight1:
                if (m + n) % 2 == 0:
                    median1 = max(maxLeft1, maxLeft2)
                    median2 = min(minRight1, minRight2)
                    return (median1 + median2) / 2.0
                    # 如果符合中位数条件,且总长度为偶数,返回两个中间值的平均数
                else:
                    median1 = max(maxLeft1, maxLeft2)
                    return median1
                    # 如果符合中位数条件,且总长度为奇数,返回较大的中间值
            elif maxLeft1 > minRight2:
                right = partition1 - 1
                # 当前分割点在nums1中太靠右,更新右边界
            else:
                left = partition1 + 1
                # 当前分割点在nums1中太靠左,更新左边界
        raise ValueError("Invalid input")
        # 没有找到符合条件的分割点,抛出异常表示输入无效

运行效果及示例代码


示例代码1


nums1 = [1, 3]
nums2 = [2]
solution = Solution()
median = solution.findMedianSortedArrays(nums1, nums2)
print("示例1的中位数为:", median)

效果图

示例代码2


nums1 = [1, 2]
nums2 = [3, 4]
solution = Solution()
median = solution.findMedianSortedArrays(nums1, nums2)
print("示例2的中位数为:", median)

效果图


完结


相关文章
|
6天前
|
机器学习/深度学习 数据采集 算法
Python用逻辑回归、决策树、SVM、XGBoost 算法机器学习预测用户信贷行为数据分析报告
Python用逻辑回归、决策树、SVM、XGBoost 算法机器学习预测用户信贷行为数据分析报告
18 1
|
4天前
|
机器学习/深度学习 运维 算法
【Python机器学习专栏】异常检测算法在Python中的实践
【4月更文挑战第30天】本文介绍了异常检测的重要性和在不同领域的应用,如欺诈检测和网络安全。文章概述了四种常见异常检测算法:基于统计、距离、密度和模型的方法。在Python实践中,使用scikit-learn库展示了如何实现这些算法,包括正态分布拟合、K-means聚类、局部异常因子(LOF)和孤立森林(Isolation Forest)。通过计算概率密度、距离、LOF值和数据点的平均路径长度来识别异常值。
|
4天前
|
机器学习/深度学习 数据可视化 算法
【Python机器学习专栏】t-SNE算法在数据可视化中的应用
【4月更文挑战第30天】t-SNE算法是用于高维数据可视化的非线性降维技术,通过最小化Kullback-Leibler散度在低维空间保持数据点间关系。其特点包括:高维到二维/三维映射、保留局部结构、无需预定义簇数量,但计算成本高。Python中可使用`scikit-learn`的`TSNE`类实现,结合`matplotlib`进行可视化。尽管计算昂贵,t-SNE在揭示复杂数据集结构上极具价值。
|
4天前
|
机器学习/深度学习 算法 数据挖掘
【Python机器学习专栏】关联规则学习:Apriori算法详解
【4月更文挑战第30天】Apriori算法是一种用于关联规则学习的经典算法,尤其适用于购物篮分析,以发现商品间的购买关联。该算法基于支持度和置信度指标,通过迭代生成频繁项集并提取满足阈值的规则。Python中可借助mlxtend库实现Apriori,例如处理购物篮数据,设置支持度和置信度阈值,找出相关规则。
|
4天前
|
机器学习/深度学习 算法 数据挖掘
【Python机器学习专栏】层次聚类算法的原理与应用
【4月更文挑战第30天】层次聚类是数据挖掘中的聚类技术,无需预设簇数量,能生成数据的层次结构。分为凝聚(自下而上)和分裂(自上而下)两类,常用凝聚层次聚类有最短/最长距离、群集平均和Ward方法。优点是自动确定簇数、提供层次结构,适合小到中型数据集;缺点是计算成本高、过程不可逆且对异常值敏感。在Python中可使用`scipy.cluster.hierarchy`进行实现。尽管有局限,层次聚类仍是各领域强大的分析工具。
|
4天前
|
机器学习/深度学习 算法 数据挖掘
【Python 机器学习专栏】K-means 聚类算法在 Python 中的实现
【4月更文挑战第30天】K-means 是一种常见的聚类算法,用于将数据集划分为 K 个簇。其基本流程包括初始化簇中心、分配数据点、更新簇中心并重复此过程直到收敛。在 Python 中实现 K-means 包括数据准备、定义距离函数、初始化、迭代和输出结果。虽然算法简单高效,但它需要预先设定 K 值,且对初始点选择敏感,可能陷入局部最优。广泛应用在市场分析、图像分割等场景。理解原理与实现对应用聚类分析至关重要。
|
4天前
|
机器学习/深度学习 算法 前端开发
【Python机器学习专栏】集成学习算法的原理与应用
【4月更文挑战第30天】集成学习通过组合多个基学习器提升预测准确性,广泛应用于分类、回归等问题。主要步骤包括生成基学习器、训练和结合预测结果。算法类型有Bagging(如随机森林)、Boosting(如AdaBoost)和Stacking。Python中可使用scikit-learn实现,如示例代码展示的随机森林分类。集成学习能降低模型方差,缓解过拟合,提高预测性能。
|
4天前
|
机器学习/深度学习 算法 Python
【Python 机器学习专栏】随机森林算法的性能与调优
【4月更文挑战第30天】随机森林是一种集成学习方法,通过构建多棵决策树并投票或平均预测结果,具有高准确性、抗过拟合、处理高维数据的能力。关键性能因素包括树的数量、深度、特征选择和样本大小。调优方法包括调整树的数量、深度,选择关键特征和参数优化。Python 示例展示了使用 GridSearchCV 进行调优。随机森林广泛应用于分类、回归和特征选择问题,是机器学习中的重要工具。
|
4天前
|
机器学习/深度学习 算法 数据可视化
【Python机器学习专栏】决策树算法的实现与解释
【4月更文挑战第30天】本文探讨了决策树算法,一种流行的监督学习方法,用于分类和回归。文章阐述了决策树的基本原理,其中内部节点代表特征判断,分支表示判断结果,叶节点代表类别。信息增益等标准用于衡量特征重要性。通过Python的scikit-learn库展示了构建鸢尾花数据集分类器的示例,包括训练、预测、评估和可视化决策树。最后,讨论了模型解释和特征重要性评估在优化中的作用。
|
5天前
|
机器学习/深度学习 算法 数据挖掘
机器学习--K近邻算法,以及python中通过Scikit-learn库实现K近邻算法API使用技巧
机器学习--K近邻算法,以及python中通过Scikit-learn库实现K近邻算法API使用技巧