【leetcode经典题目】寻找两个正序数组的中位数

第4题,难度hard,思想方法是很巧妙的一种二分思想,但是不是严格意义的二分法。
在这里插入图片描述

如果不考虑时间复杂度,可以维护一个采用双指针的方法,分别从两个数组的头开始查找,然后找到k大的数字,时间复杂度是 O ( n + m ) O(n+m) O(n+m)

但是这里限制了时间复杂度是lg级别的,因此很自然的想到采用二分的策略。
在这里插入图片描述

进一步解释,每次我们分别对两个数组进行查找,找到的两个target中小的那个必然是不满足的,因为小于这个数字的只有 k − 2 k-2 k2个,算上自身也只有 k − 1 k-1 k1。我们删除这些数字(或者坐标进行偏移),相应的修正下一次需要寻找的k,重复计算。

那么结束循环的条件是什么呢?当k是1的时候,表示需要找到剩余数字中第一小的,因此返回min(nums1[index], nums2[index])就可以。

但是还有两个特殊的情况,就是当某个数组查询到了该数组最大的元素时候,依然无法满足第k小(考虑nums1的全部元素都小于nums2),此时也可以直接结束循环,因为很明确第k小的元素一定在nums2中(实际上两个数组直接合并就是有序的了)。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        def findkelement(k):
            index1 = 0
            index2 = 0
            while True:
            	## 考虑可以返回的条件,某一个数组查询到了边界或者需要得到最小的那个
                if index1 == n:
                    return nums2[index2+k-1]
                if index2 == m:
                    return nums1[index1+k-1]
                if k == 1:
                    return min(nums1[index1], nums2[index2])
                
                ## 在细节上需要多家注意,坐标对应的元素个数关系
                new_index1 = min(index1 + k//2 - 1, n-1)# 保证大于k//2-1个,且不能超出边界
                new_index2 = min(index2 + k//2 - 1, m-1)
                target1 = nums1[new_index1]
                target2 = nums2[new_index2]
                if target1<=target2:
                    k -= new_index1-index1+1  # 包括自身在内的前面所有数组删除
                    index1 = new_index1 + 1
                else:
                    k -= new_index2-index2 + 1
                    index2 = new_index2 + 1

        n = len(nums1)
        m = len(nums2)
        total = n+m
        # 对于数组的元素和是奇数还是偶数的问题,如上面的分析
        if total&1:
            return findkelement((total)//2+1)
        else:
            return (findkelement((total)//2)+findkelement((total)//2+1))/2

还有另外的方法可以将时间复杂度降低到 O ( l g ( m i n ( n , m ) ) ) O(lg(min(n,m))) O(lg(min(n,m))),但是需要用到数学的推导,参考题解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值