leetcode刷题_day3_(array)_code4(寻找两个有序数组的中位数)

困难题
需要时间复杂度为log(m+n)

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解答:

  1. 通过题目要求的log(m+n),可以确定是要使用二分法进行解题。
  2. 考虑如何二分,首先想到同时二分,上下两个数组轮流进行二分然后比较大小决定下一步的二分形式。但是发现太过复杂,类似于二元方程的效果了。参考答题解说,可以确定数组A中值以后,以半数的元素来得到B的临界点。这样就变成了一元方程。然后通过判断临界条件确定是否需要继续对A数组进行二分。i=(left + right)//2, j = (m+n+1)//2 -i。(这里的left起始值为0,right起始值为m(而不是m-1),同时避免j变为负数,提前判断mn大小,交换操作保证m<=n
    len1 = len(nums1)
    len2 = len(nums2)
    a = (left +right)//2
    b = (len1 + len2 +1)//2 -a
  1. 分析中值: 为什么是这样的等式? 假如和为偶数,中值应该正好为(m+n)/2,也就是i+j=(m+n)/2,此时中值为(max(A[i-1],B[j-1])+min(A[i],B[j]))/2。 假如和为奇数我们要使多出来的值分配在左边,那么i+j=(m+n+1)/2,此时中值应该为max(A[i-1],B[j-1])。(此处考虑一般条件,边界条件后面讨论)
  2. 寻找临界条件:什么情况下刚好就是两个数组的中值。
    在这里插入图片描述
    A[i-1] <= A[i] B[j-1]<=B[j]恒成立。 要想满足中值条件,需要
    左边部分恒小于等于右边部分。即条件为:A[i-1]<=B[j] and B[j-1]<=A[i](此处考虑一般条件,边界条件后面讨论)
  3. 寻找迭代条件:什么情况下进行迭代。A[i-1]>B[j] or B[j-1]>A[i],二者发生的情况处于一个分界的地位,二选一发生,可以进入if else的选择判断中。A[i-1]>B[j] 时,证明A选取的元素太小了,需要增大,向右继续二分,即返回**((left + right)//2 +1,right);反之则返回(left,(left + right)//2 -1)**。这个基本和普通的二分查找一样了。
  4. 寻找边界条件(临界条件中的边界):(A[i-1]<=B[j] and B[j-1]<=A[i]):当i=0时,不存在i-1了,也就是max_left不应该通过比较选取max了,默认就是B[j-1]。同理,当j=0时,max为A[i-1]。(一般情况为max(A[i-1],B[j-1]));然后看如果需要右边决定中值的情况(m+n为偶数)。这里需要再做判定,如果i=m,不存在A[m],所以此时min为B[j];反之j=n时,不存在B[n],所以此时min为A[i]。
        if a==0:
            max_left = nums2[b-1]
        elif b==0:
            max_left = nums1[a-1]
        else:
            max_left = max(nums1[a-1],nums2[b-1])

        if (len1 + len2) % 2 == 0:

            if a==len1:
                min_right = nums2[b]

            elif b==len2:
                min_right = nums1[a]

            else:
                min_right = min(nums1[a],nums2[b])
            print(max_left, min_right)
            return (max_left + min_right)/2
        else:
            return max_left
  1. 寻找边界情况(迭代条件里的边界):迭代的时候遇到了i=0,有i=1迭代过来,或者本身具有这个属性,这个时候意味着(从i=1得到,A[0]>B[j],进入下一步时,A[0]自然而然地进入了右边部分不参与max的比较了)直接进入临界情况进行取值。同理j=0,i=m,j=n都一样也就是变为else表示临界情况)。然后迭代里面要保证运行,需要能满足条件,即A[i-1]>B[j]时,i>0;B[j-1]<=A[i],i<m(为什么不用j判断?因为j由i产生,如果仅仅满足j>0,会造成i溢出(因为m<=n))
    if a>0 and nums1[a-1] > nums2[b]  :
        print('2#')
        return midvalue(left,a-1,nums1,nums2)
    elif  a<len1 and nums2[b-1] > nums1[a] :
        print('1#')
        return midvalue(a+1,right,nums1,nums2)

    else:
  1. 总结:一般来说(如果一开始边界那就直接进入临界态),先进入迭代,然后到达一般状态下的临界或者边界状态(边界直接进入临界状态,因为边界就满足临界状态,只用看单一数组就行),然后临界状态根据值进行判断生成中值。
  2. 代码:
def findMedianSortedArrays(nums1, nums2):
    len1=len(nums1)
    len2=len(nums2)
    if len1 <= len2:
        return midvalue(0,len1,nums1,nums2)
    else:
        return midvalue(0,len2,nums2,nums1)

def midvalue(left,right,nums1,nums2):
    len1 = len(nums1)
    len2 = len(nums2)
    a = (left +right)//2
    b = (len1 + len2 +1)//2 -a
    print(left,right,a,b)
    #print(a,b,nums2[b-1],nums1[a])
    if a>0 and nums1[a-1] > nums2[b]  :
        print('2#')
        return midvalue(left,a-1,nums1,nums2)
    elif  a<len1 and nums2[b-1] > nums1[a] :
        print('1#')
        return midvalue(a+1,right,nums1,nums2)

    else:
        #nums1[a-1] <= nums2[b] and nums2[b-1]<= nums1[a]:
        print('3#')
        if a==0:
            max_left = nums2[b-1]
        elif b==0:
            max_left = nums1[a-1]
        else:
            max_left = max(nums1[a-1],nums2[b-1])

        if (len1 + len2) % 2 == 0:

            if a==len1:
                min_right = nums2[b]

            elif b==len2:
                min_right = nums1[a]

            else:
                min_right = min(nums1[a],nums2[b])
            print(max_left, min_right)
            return (max_left + min_right)/2
        else:
            return max_left

y = findMedianSortedArrays([100001],[100000])
print(y)

code里面我用nums代表的A B ,然后a b 代表的i j。
这道题真的很难,想了很久才只能搞得半懂,以上解释思想也只是我看了答案以后的解释。解释过程可能存在纰漏,望大家指正讨论!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值