leetcode 寻找两个有序数组的中位数 白痴讲解

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

题目描述:

在这里插入图片描述

方法一

将两个数组拼接,然后排序,根据中位数的定义来求中位数。

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        nums = nums1 + nums2
        nums.sort()
        length = len(nums)
        if length % 2 == 0:
        #如果是个数是偶数,根据中位数的定义
        #将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
        #就只能取中间两个数的平均值
            return (nums[length // 2 - 1] + nums[(length // 2)])/2
        #如果个数是奇数,正好有一个数在中间,将两边的数分成个数相同的集合。
        return nums[length // 2]  

方法二:

递归法
具体参考的是leetcode官网的参考答案

https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/

下面我用自己的话给予补充解释一遍。
首先重申中位数的定义:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
我们有两个有序的数组A(m个元素)、B(n个元素)。
i , j i,j i,j两个下标来分别划分成两部分。
这里以A为例。
在这里插入图片描述
那么A一共有m+1种划分方法。
在这里插入图片描述
B也同理。
在这里插入图片描述

在这里插入图片描述
上面的等价条件可以写成
l e n ( l e f t p a r t ) = l e n ( r i g h t p a r t ) len(leftpart)=len(rightpart) len(leftpart)=len(rightpart)
等价于
i = 0   m , j = ( m + n + 1 ) / / 2 − i i=0~m,j=(m+n+1)//2-i i=0 m,j=(m+n+1)//2i
注意是地板除,原答案写了/。
关于这部分应该是有问题的。
m+n是偶数,两边的个数都能一样
m+n是奇数的时候不行,左边会比右边多一个。
所以这个条件 l e n ( l e f t p a r t ) = l e n ( r i g h t p a r t ) len(leftpart)=len(rightpart) len(leftpart)=len(rightpart)不是必要的
后面我会写一个具体的例子。

m a x ( l e f t p a r t ) ≤ m i n ( r i g h t p a r t ) max(leftpart)≤min(rightpart) max(leftpart)min(rightpart)
等价于
B [ j − 1 ] ≤ A [ i ] 且 A [ i − 1 ] ≤ B [ j ] B[j-1]≤A[i]且A[i-1]≤B[j] B[j1]A[i]A[i1]B[j]
下面我补充这个条件的由来。
在这里插入图片描述

接着就是算法的具体过程。这里答案写的很明白我就不多补充了。
在这里插入图片描述
注意这里有n≥m的假定,其实只要想一想就能明白,如果n、m的大小关系是反的,把两个数组颠倒一下就可以了,大的叫B,小的叫A。
在这里插入图片描述
在这里插入图片描述

举个例子方便大家理解。
在这里插入图片描述

在这里插入图片描述

这样就能加深对算法的理解了。
接下来时临界值的情况,这里答案说的比较清楚。
在这里插入图片描述
在这里插入图片描述

也就是出现临界值时,我们关键的判断条件 B [ j − 1 ] ≤ A [ i ] 且 A [ i − 1 ] ≤ B [ j ] B[j-1]≤A[i]且A[i-1]≤B[j] B[j1]A[i]A[i1]B[j],有时候都不需要判断,或者只要判断其中一边,下面附上代码。

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        m, n = len(nums1), len(nums2)
        if m > n:
            nums1, nums2, m, n = nums2, nums1, n, m
            #和前面说的一样,m、n大小关系相反时,只需要将两个数组颠倒一下就可以了。
        if n == 0:
            raise ValueError

        imin, imax, half_len = 0, m, (m + n + 1) // 2
        while imin <= imax:
            i = (imin + imax) // 2
            j = half_len - i
            #这里写的时普通情况
            if i < m and nums2[j-1] > nums1[i]:
                # i 太小,需要增大i
                imin = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:
                # i 太大,需要减小i
                imax = i - 1
            else:
                # 如果上面两边的判定条件都满足,i直接就是答案

               #下面是临界值的情况
                if i == 0: max_of_left = nums2[j-1]
                elif j == 0: max_of_left = nums1[i-1]
                else: max_of_left = max(nums1[i-1], nums2[j-1])

                if (m + n) % 2 == 1:
                    return max_of_left

                if i == m: min_of_right = nums2[j]
                elif j == n: min_of_right = nums1[i]
                else: min_of_right = min(nums1[i], nums2[j])

                return (max_of_left + min_of_right) / 2.0


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值