当前位置: 首页 > news >正文

LeetCode:寻找两个正序数组的中位数----多种解题方式

在这里插入图片描述

文章目录

    • 题目
    • 举例
    • 思路一 运用归并排序的思想,双指针
    • 思路二 运用归并排序的思想,双指针
    • 思路三 使用二分查找法

写在前面:在学习算法中我们会学到很多经典的算法,双指针,二分查找等等,但是这只是一种思想,解题时我们可以灵活的运用,也不必局限一种形式,要将学到的东西,转换成自己的东西。

题目

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

注意本题在力扣中不用返回的数据不用考虑小数位数,系统会自动保留对应的位数

思路一 运用归并排序的思想,双指针

因为这是两个有序数组,在两个有序数组中寻找中位数,可以先考虑将两个数组合并起来,然后找中位数

有序数组的合并比较简单,就是用两个指针分别指向两个数组的开头,依次比较指针指向的数字,较少的数字添加到新数组,指针加1,然后再重复以上的循环,直至其中一个指针越界。最后将未添加完的数字合并到新数组

详细的流程看代码

def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    l1 = 0
    l2 = 0
    r1 = len(nums1)
    r2 = len(nums2)
    arr = []
    while True:  # 循环添加
        if l1>r1-1 or l2>r2-1:  # 当有一个数组的数据被添加完成,就跳出循环
            break
        if nums1[l1] > nums2[l2]:
            arr.append(nums2[l2])
            l2+=1
        else:
            arr.append(nums1[l1])
            l1+=1
	# 添加未合并完成的数组
    if l1!=r1:
        arr.extend(nums1[l1:])
    elif l2!=r2:
        arr.extend(nums2[l2:])
    # 根据数组长度的奇偶返回不同的值
    if (r1+r2)%2==0:
        return (arr[((r1+r2)//2)-1]+arr[(r1+r2)//2])/2
    else:
        return arr[(r1+r2)//2]

我们能发现上面这个解题方式中,我们使用了额外的一个数组,浪费了内存空间,因为是两个有序数组,目的又是找出中位数,所以我们可以直接找出中位数,而不用进行合并

思路二 运用归并排序的思想,双指针

这个算法也是用了两个指针,使用情况同第一个类似,只不过我们比较大小后不进行合并,就是用应给变量记录比较的次数,直至比较的次数==中位数的位置,此时我们再根据具体的情况返回具体的值
具体的思路请看代码

def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    l1 = 0 
    l2 = 0
    r1 = len(nums1)
    r2 = len(nums2)
    number = 0   # 记录次数
    f = 0 # 标志数组是奇数还是偶数
    
    # 根据奇偶设置中间的元素位置
    if (r1+r2)%2==0: 
        f = 2
        mid = (r1+r2)//2   
    else:
        f = 1
        mid = (r1+r2)//2+1
        
    while True:
        if l1>r1-1 or l2>r2-1:
            break
        if nums1[l1] > nums2[l2]: 
            number+=1
            if number == mid: # 当number等于mid的时候就代表此时已经到了中位数的位置
                if f==1:   # 奇数情况
                    return nums2[l2]  
                else:      # 偶数情况
                    if l2==r2-1:  # 此时l2指向其中nums2的最后一个元素
                        return (nums2[l2]+nums1[l1])/2
                    else:
                    	# 返回两种情况中最小的
                        return min(nums2[l2]+nums2[l2+1],nums2[l2]+nums1[l1])/2
            l2+=1 
        else:   # 同上思想一样,对象更换了一下
            number+=1
            if number == mid:
                if f==1:
                    return nums1[l1]
                else:
                    if l1==r1-1:
                        return (nums2[l2]+nums1[l1])/2
                    else:       
                        return min(nums1[l1]+nums1[l1+1],nums2[l2]+nums1[l1])/2
            l1+=1
        
    # 这种是当一个数组特别长,中位数在其中一个数组中的情况
    if l1!=r1:
        if f==1:
            return nums1[mid-l2-1]
        else:
            return (nums1[mid-l2-1]+nums1[mid-l2])/2
    elif l2!=r2:
        if f==1:
            return nums2[mid-l1-1]
        else:
            return (nums2[mid-l1-1]+nums2[mid-l1])/2

此时我们能够发现上面的两种解法的时间复杂度不是 O(log (m+n)),原因就是我们合并和排除数字都是一个一个的进行的 时间复杂度为 O(m+n)
想要实现O(log (m+n))的时间复杂度,我们可以回想一下什么情况出现log二分法,此时我们的思路就明朗了,解题需要使用二分的思想,每次排除的数字,都应该是原数据的二分之一

思路三 使用二分查找法

在这里插入图片描述

在这里插入图片描述

def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    if len(nums1) > len(nums2):
    	# 保证数组nums1是较短的哪一个
        return self.findMedianSortedArrays(nums2, nums1)

    infinty = 10*6+1  # 
    m, n = len(nums1), len(nums2)
    left, right = 0, m  # 只需要记录记录第一个数组的指针,第二个数组可以计算出来
    # median1:前一部分的最大值
    # median2:后一部分的最小值
    median1, median2 = 0, 0

    while left <= right:   # 循环条件
        # 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]
        # // 后一部分包含 nums1[i .. m-1] 和 nums2[j .. n-1]
        i = (left + right) // 2   # 通过计算确定二分后的中间位置 nums1
        j = (m + n + 1) // 2 - i  # 根据规则计算nums2的需要分的位置
        
       # nums_im1, nums_i, nums_jm1, nums_j 分别表示 nums1[i-1], nums1[i], nums2[j-1], nums2[j]
        # 四个数字 看数字是否符合条件
        nums_im1 = (-infinty if i == 0 else nums1[i - 1])  # 当i为0时
        nums_i = (infinty if i == m else nums1[i])
        nums_jm1 = (-infinty if j == 0 else nums2[j - 1])  # 当j为0时
        nums_j = (infinty if j == n else nums2[j])

        if nums_im1 <= nums_j: 
        	# 满足这个条件的median1, median2 不一定时最后结果,但是最后结果一定满足这个条件
			# 当出现最后结果 left将不在改变,直至循环结束
            median1, median2 = max(nums_im1, nums_jm1), min(nums_i, nums_j)
            # 取分割线左侧的最大值,取分割线右侧的最小值
            left = i + 1
        else:
            right = i - 1
	# 根据奇偶的不同返回不同的结果
    return (median1 + median2) / 2 if (m + n) % 2 == 0 else median1

最后一个我自己的代码太罗嗦了,就使用的是力扣官方的代码。
具体的讲解请大家移步力扣官方

相关文章:

  • 超实用的JS常用算法详解(推荐)
  • 分布式版本控制系统Git的下载、安装与使用其复制GitHub项目代码的方法
  • 金仓数据库KingbaseES物理备份恢复最佳实践(执行备份)
  • 【CSS】表格、定位_普通流定位与浮动定位、其他css常用属性_05
  • 没有学过C语言可以学Java吗?
  • 网络安全学习路线
  • 指针(四)- 函数指针和回调函数
  • 【职场必备知识】成都购房政策调研
  • 什么是xhr?XMLHttpRequest的基本使用及xhr Level2的新特性详解及案例
  • VMware-安装 CentOs-Linux 操作系统
  • 【老生谈算法】matlab实现LMS算法的自适应滤波算法源码——自适应滤波
  • Springboot 玩一玩代码混淆,防止反编译代码泄露
  • 【配电网重构】基于matlab负荷平衡的配电网重构【含Matlab源码 2180期】
  • 计算机网络---第二章物理层---通信基础
  • 【JAVA问题解决方案】01.EasyExcel导出数据超过Excel单表上限解决方案
  • 《剑指offer》分解让复杂问题更简单
  • 【391天】每日项目总结系列128(2018.03.03)
  • 2018一半小结一波
  • 2019年如何成为全栈工程师?
  • android 一些 utils
  • Android组件 - 收藏集 - 掘金
  • Bytom交易说明(账户管理模式)
  • cookie和session
  • golang中接口赋值与方法集
  • happypack两次报错的问题
  • Java 多线程编程之:notify 和 wait 用法
  • Just for fun——迅速写完快速排序
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • nfs客户端进程变D,延伸linux的lock
  • php面试题 汇集2
  • Theano - 导数
  • 分布式熔断降级平台aegis
  • 来,膜拜下android roadmap,强大的执行力
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 我的业余项目总结
  • 无服务器化是企业 IT 架构的未来吗?
  • 小程序测试方案初探
  • 延迟脚本的方式
  • 在Unity中实现一个简单的消息管理器
  • 《码出高效》学习笔记与书中错误记录
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • # include “ “ 和 # include < >两者的区别
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • (+4)2.2UML建模图
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (算法)Game
  • (转)一些感悟
  • (转载)从 Java 代码到 Java 堆
  • .a文件和.so文件
  • .chm格式文件如何阅读
  • .gitignore文件—git忽略文件