LeetCode in Python 4. Median of Two Sorted Arrays (寻找两个正序数组的中位数)

寻找两个正序数组的中位数可以通过两种方法实现,一是先将两个数组排序然后根据数组长度找到合并后数组的中位数,此种方法时间复杂度为O(m+n),m和n分别是两个数组长度。二是利用二分查找的思想,此种方法可将时间复杂度降至O(log(m+n)),具体实现图解可见图1-2。本文主要给出方法二的代码实现。

示例:

图1 奇偶长度下两数组中位数取法(图源:@花花酱)

图2  具体示例分析(图源:@花花酱)

代码:

class Solution:
    def findMedianSortedArrays(slef, nums1, nums2):
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        total = len(nums1) + len(nums2)
        half = total // 2
        
        l1, r1 = 0, len(nums1) - 1
        
        while True:
            m1 = (l1 + r1) // 2
            m2 = half - m1 - 2
        
            left1 = nums1[m1] if m1 >= 0 else float("-inf")
            right1 = nums1[m1+1] if m1+1 < len(nums1) else float("inf")
            left2 = nums2[m2] if m2 >= 0 else float("-inf")
            right2 = nums2[m2+1] if m2+1 < len(nums2) else float("inf")

            if left1 <= right2 and left2 <= right1:
                if total % 2:
                    return min(right1, right2)
                else:
                    return (max(left1, left2) + min(right1, right2)) / 2
            elif left1 > right2:
                r1 = m1 - 1
            else:  #left2 > right1
                l1 = m1 + 1

解释:

1)取两数组合并后的一半,m1为nums1所取最后一个元素下标,m2为nums2所取最后一个元素下标。两个数组所取元素的数量和即为半个数组长度,即half。此处需注意下标取法。

         m1 = (l1 + r1) // 2
         m2 = half - m1 - 2

        m1的取法很好理解,左右指针的mid指针位,而m2之所以要-2,一是m1为nums1所取最后一个元素下标,nums1取出的元素个数为m1+1,故应该在nums2中取剩下half-(m1+1)个元素。在nums2中取出第half-(m1+1)个元素的下标为half-(m1+1)-1(数组下标从0开始),即m2=half-m1-2。

2)left1,left2分别对应nums1和nums2的左中位数,right1,right2为两者的右中位数

        left1 = nums1[m1] if m1 >= 0 else float("-inf")
        right1 = nums1[m1+1] if m1+1 < len(nums1) else float("inf")
        left2 = nums2[m2] if m2 >= 0 else float("-inf")
        right2 = nums2[m2+1] if m2+1 < len(nums2) else float("inf")

        这里的判断条件即为下标是否溢出的判断,对于左中位数而言如果该下标<0即表示数组最左边,设置为-∞,反之,若又中位数超出数组范围,在数组最右边,则设置为+∞。

3)对于算法主体的理解:即根据左右中位数的大小关系来判断各个数组所取元素是否有失偏颇,若num1的左中位数即left1<=nums2的右中位数right2且同时num2的左中位数即left2<=nums1的右中位数right1,则说明取出的half个元素确实是两个数组合并后最小的half个元素。若left1 > right2,即nums1中的元素取多了,num2中还有比nums1所取元素中更小的元素,因此对nums1的右指针进行更新,右指针左移至m1-1,减少从nums1中取的元素数量。同理,若left2 > right1,则说明从nums2中取得元素多了,nums1中还存在比从nums2中取的元素更小的元素,此时更新nums1的左指针,移至m1+1,增加从nums1中取出的元素数量。重复直至找到一个合适的m1使得从两个数组中取出的元素为合并两数组后最小的half个元素。   

        if left1 <= right2 and left2 <= right1:

                if total % 2:

                        return min(right1, right2)

                else:

                        return (max(left1, left2) + min(right1, right2)) / 2

                elif left1 > right2:

                        nums1_r = nums1_m - 1

                else:

                        nums1_l = nums1_m + 1

4)对于数组奇偶元素个数的分开判断,如果数组有奇数个元素,则中位数应该是取完half(此half为向下取的整数)后两个数组右中位数的最小值,举例说明,有13个元素,half=6,中位数应为两数组合并后第7个元素,而第7个元素来源只能是取完half个数后两数组的右中位数中的一个,即right1和right2中的一个,根据正序排列的顺序,小的在前大的在后,故第7个元素应为min(right1, right2)。若数组有偶数个元素,中位数应该是合并后数组最中间两个元素的平均事,最中间两个数的来源只能源自left1, left2和right1, right2,仍然是根据正序排列,要取两数组左中位数中的最大值和右中位数中的最小值作为最中间的两个元素,即max(left1, left2) 和 min(right1, right2)),最后求两者平均数即可。

另附上合并两个有序数组代码:

LeetCode in Python 88. Merge Sorted Array (合并两个有序数组)-CSDN博客

  • 47
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值