Median of Two Sorted Arrays

题:

There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

算法:

一个解法是把逐个比较两个列表中的数字然后按照顺序合并,取合并后的数组的中位数。复杂度为O(m+n)。
在油管上学习了一种利用Binary Search来解题的方法1,很有趣。O(log(min(m, n)),跑出来在92%左右。基本思路如下图:
在这里插入图片描述

由于两个数组已经是有序的了,则若可以把每个数组分成两部分,使得每一个左半部分都小于所有的右半部分,并且左半部分的总个数等于右半部分的总个数(或者相差一个,这个在后面会有说明),那么中位数就可以在分割的位置中得到了。而在寻找这两个合适的分割点的过程中,只需要关心一个数组分割点的左部最大值 X l e f t X_{left} Xleft X r i g h t X_{right} Xright是否小于另一个数组分割点的右部最小值 Y r i g h t Y_{right} Yright Y r i g h t Y_{right} Yright,如果不满足则要往相应的方向移动,提升算法速度的一大关键在于移动采用的是二分法(i.e. end = xright - 1or start = xleft + 1)。

实现:

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        if len(nums1) > len(nums2):
            t = nums1
            nums1 = nums2
            nums2 = t
        len_x = len(nums1)
        len_y = len(nums2)
        len_ttl = len_x + len_y
        start_x = 0
        end_x = len_x ## don't need to -1
        # start_y = 0
        # end_y = len_y 
        # for i in range(3):
        while start_x <= end_x: # it's okay to have = since the if below can take care of the = case
            print("endx", end_x)
            a = (start_x + end_x) // 2 ## partion of x
            print("a", a)
            b = (len_ttl + 1) // 2 - a ## corresponding partition of y
            if len_x == 0:
                xleft = -float('Inf')
                xright = float('Inf')
            elif a == 0:
                xleft = -float('Inf')
                xright = nums1[a]
            elif a == len_x:
                xright = float('Inf')
                xleft = nums1[a - 1]
            else:
                xleft = nums1[a - 1]
                xright = nums1[a]
            print('b',b)
            if len_y == 0:
                yleft = -float('Inf')
                yright = float('Inf')
            elif b == 0:
                yleft = -float('Inf')
                yright = nums2[b]
            elif b == len_y:
                yright = float('Inf')
                yleft = nums2[b - 1]
            else:
                yleft = nums2[b - 1]
                yright = nums2[b]
            print(xleft, xright, yleft, yright)
            if (xleft <= yright) & (yleft <= xright):
                # print(xleft, xright, yleft, yright)
                if len_ttl % 2 == 0:
                    median = (max(xleft, yleft) + min(xright, yright)) / 2
                    return median
                else:
                    median = max(xleft, yleft)
                    return median
            elif xleft > yright:
                end_x = a - 1 ## -1 to exclude the previous xleft. xleft is a num instead of an index!
            else: # xright < yleft 
                start_x = a + 1

虽然算法的理解不难,但实现起来还是费了一番功夫。主要耗费的时间在于界定边界和极端情况。几个要关注的点:

  1. 两个分割点之和 a + b = l e n g t h 1 + l e n g t h 2 2 a+b=\frac{length_1+length_2}{2} a+b=2length1+length2这能使当合并数组长度为基数的时候,中位数总在分割点的左边出现。
  2. 始终让数组x代表较短的数组,否则算数组y的分割点b的时候容易超出数组范围。
  3. 二分法中的起始点的确定 end = xright - 1or start = xleft + 1,暂时还没有想明白为什么,但只用end = xright会没办法应对某些特殊情况。
  4. 前半部分的一连串if else想了挺久的,暂时归纳不出好的方法论,只能常看常新了。

思考:

  1. 要利用好两个数组以排序这个点,即认真审题,利用好每一个条件。
  2. 边界的划分能力还需要提高,代码实现很大的一个关键在于对边界和极端情况的界定。
  3. 极端情况可以从算法中需要的几个值不存在的情况入手,比如这里由于要知道分割点左右两边的数字,则要考虑左右没有数字的情况(分割点在最左边,分割点在最右边,空数组等)。
  4. 多写: )

  1. https://www.youtube.com/watch?v=LPFhl65R7ww ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值