LeetCode 4. Median of Two Sorted Arrays

本文介绍了一种高效算法,用于查找两个已排序数组的中位数,时间复杂度为O(log(min(m,n)))。通过二分搜索确定中位数的位置,确保两边元素数量相等。

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)).
You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]
The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

题目大意:题意较简单,就是找出两个排好序的数组合并后的中位数。
解题思路:由于本题要求时间复杂度为O(log(m+n)),所以自然想到二分搜索,但是问题在于搜索什么?二分搜索最重要的就是搜索停止条件,以及什么情况下向左转移什么情况下向右。
本题的突破口在于中位数,中位数的含义就是将数组从小到大排列后,中位数左右的数的数量是相同的。两个数组的元素个数是确定的,这样最后得到的中位数左右的元素个数也是确定的,我们选择其中一个数组进行二分搜索,搜索该数组中有多少元素在最终的中位数的左边,左边的个数确定了右边自然也确定了,同时第二个数组中的左右边的个数也确定了。有了这个思路就可以对两个数组中元素较少的数组进行搜索(主要是为了降低复杂度),这样整个算法的时间复杂度就是O(log(min(m, n)))。

代码:

def findMedianSortedArrays(nums1, nums2):
    # 先找出两个数组中元素较少的数组,默认情况下认为nums1元素个数少于nums2
    if len(nums1) > len(nums2):
        temp = nums2
        nums2 = nums1
        nums1 = temp
    # assert len(nums1) <= len(nums2)
    n1, n2 = len(nums1), len(nums2)
    if n1 == 0:
        nums2.sort()
        # print("num2", nums2)
        if n2 % 2 == 1:
            return nums2[(n2 - 1) // 2]
        else:
            return (nums2[n2 // 2 - 1] + nums2[n2 // 2]) / 2.0
    # nums1 n1个元素, nums2 n2个元素
    # 合并后分割线的左边应该有 (n1 + n2 + 1) / 2个元素  
    # 例如 1 2 |  3    "|" 为中位线分割线  3个数分割线左边有2个
    # 1 2 | 3 4                         4个数分割线左边有2个
    # 所以现在的目的就是在nums1数组中搜索正确的分割线

    left, right = 0, len(nums1)    # 搜索边界,含义就是nums1中被归在左边的元素的个数的左右边界
    while left <= right:
        nums1_left = (left + right) // 2  # nums1中位于分割线左边的数字的个数
        nums2_left = (n1 + n2 + 1) // 2 - nums1_left     # nums2中位于分割线左边的数字的个数
        nums1_left_value = -float("inf") if nums1_left == 0 else nums1[nums1_left - 1]   # 有可能0个,这时填补-inf
        nums2_left_value = -float("inf") if nums2_left == 0 else nums2[nums2_left - 1]
        nums1_right_value = float("inf") if nums1_left >= n1 else nums1[nums1_left]
        nums2_right_value = float("inf") if nums2_left >= n2 else nums2[nums2_left]

        if nums1_left_value <= nums2_right_value and nums2_left_value <= nums1_right_value:
            left_max = max(nums1_left_value, nums2_left_value)
            right_min = min(nums1_right_value, nums2_right_value)
            if (n1 + n2) % 2 == 0:
                return (left_max + right_min) / 2.0
            else:
                return left_max
        elif nums1_left_value > nums2_right_value:
            right = nums1_left - 1
        else:
            left = nums1_left + 1


examples = [
    [[1], [2]],
    [[1, 2], [-1, 3]],
    [[1, 2], [3]],
    [[1, 2], [3, 4, 5]],
    [[1], [2, 3, 5, 6]],
    [[1, 3], [2]],
    [[1, 2], [3, 4]],
    [[1], [2, 3, 4]]
]

for num1, num2 in examples:
    print(num1, num2, ":")
    print(findMedianSortedArrays(num1, num2), findMedianSortedArrays([], num1 + num2))

参考链接:
https://www.youtube.com/watch?v=LPFhl65R7ww&t=479s

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值