leetcode 4——官方题解的翻译版

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

 

好的,看了这个题目首先要注意的一点是时间复杂度问题,我们必须要在log时间内算出,要不一合并就完事了嘛。

官方题解说了一大堆,说白了是用二分搜索寻找分割点。

首先想一个事情,如果一个序列a0,a1....an是有序的,那么我们如何寻找这个中位数呢?

我们想到的是分奇数个还是偶数个(题目已经给了提示了)假如是2k个数字 比如 0,1,2,3,4,5六个数

我们应该返回(2+3)/2那就是2.5,就是说(A[k-1]+A[k])/2

如果是奇数个比如0,1,2,3,4, 2k+1个数字应该返回A[k-1]=2。

那么当有2个序列呢?我们可以把序列“假象一样”合并起来。

比如序列1:1,3,5,7

       序列2:2,4,6,8,10,12

一共10个数字,那么我们要的是第5和第6个数字。

线性的搜索一下那就是:遍历序列1,当我分成1   3,5,7时,为了分成两半我们就要把序列2分为  2,4,6,8     10,12

因为只有这样才能保证左右合并后各一半嘛。

但是我们这样并不满足条件,因为左半边最大值:8是比右半边最小值:3还要大的。那么这样的话我们就要继续搜索。

我发现分成1,3   5,7  和2,4,6    8,10,12  时恰好满足条件。所以用左半边最大值6与右半边最小值5取中间值5.5就是答案。

综合来看,实际上我们要寻找的是这样的一个划分点:

1、保证A序列左半边和B序列左半边长度为长度和的一半(实际上也可能比一半少1)。

2、满足1的前提下应当左半部分最大值小于等于右半部分最小值。

那么线性搜索再分割就十分容易理解了。接下来想一想如何用二分搜索法来寻找这个点。

 

总的概括这个过程就是,当分割点选的“太小”,就把右边界左移,“太大”把左边界右移(是不是很像二分查找法)

class Solution:
    def findMedianSortedArrays(self, nums1, nums2) -> float:
        M,N=len(nums1),len(nums2)
        if M==0:
            return nums2[N//2] if N%2!=0 else (nums2[N//2]+nums2[N//2-1])/2
        elif N==0:
            return nums1[M//2] if M%2!=0 else (nums1[M//2]+nums1[M//2-1])/2
        else:
            if M>N:
                nums1,nums2=nums2,nums1
                N,M=M,N
            half=(M+N+1)//2
            lo,hi=0,M
            while lo<=hi:
                i=(lo+hi)//2
                j=half-i
                print("i=",i," j=",j)
                if i<hi and nums2[j-1]>nums1[i]:
                    lo=i+1
                elif lo<i  and nums1[i-1]>nums2[j]:
                    hi=i-1
                else:
                    if i==0:
                        left_max=nums2[j-1]
                    elif j==0:
                        left_max=nums1[i-1]
                    else:
                        left_max=max(nums1[i-1],nums2[j-1])
                    if i==M:
                        right_min=nums2[j]
                    elif j==N:
                        right_min=nums1[i]
                    else:
                        right_min=min(nums2[j],nums1[i])
                    return (left_max+right_min)/2 if (M+N)%2==0 else left_max

顺带说一句,如果不按照题解先把nums1变成短的那个,那变量j就会莫名其妙越界。试了几组数据都这样。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值