LeetCode:4. Median of Two Sorted Arrays

博客围绕LeetCode第4题,即求两个有序数组的中值展开。介绍了两种思路,思路一是将两个数组分割,保证左右两部分长度关系及大小关系来求中值;思路二是转化为求第K小的值,从k/2开始在两数组中寻找,还给出了Python代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode:4. Median of Two Sorted Arrays

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

求两个数组的中值(可能不是数组中的值)。

思路一

这是官方提供的一种思路。如果我们想象把A数组分为leftA和rightA两部分,把B数组分为leftB和rightB两部分。然后leftA和leftB组成leftPart,rightA和rightB组成rightPart。我们只要保证下面两种条件:

  1. leftPart长度和rightPart长度相等,或者只相差1(假设leftPart比rightPart多一个)
  2. leftPart的最大值小于rightPart的最小值

那我们就可以得到中值一定是如下两种情况:

  1. 如果两边长度相等,中值median = (max_of_left + min_of_right) / 2.0
  2. 如果两者长度相差1,那么中值median肯定是左边的最大值max_of_left

其实这个做法就是将两个数组中较小部分合并到一个共同数组leftPart中,将两个数组中较大部分合并到一个共同数组rightPart中。然后再取中值就很方便了。

Python 代码实现

class Solution(object):
    def findMedianSortedArrays(self, A, B):
        m, n = len(A), len(B)
        if m > n:
            A, B, m, n = B, A, n, m
        if n == 0:
            raise ValueError

        imin = 0 
        imax = m
        half_len = ((int)((m + n + 1) / 2))
        print("imin : %d, imax : %d , half_len : %d"%(imin,imax,half_len))
        while imin <= imax:
            i = (int)((imin + imax) / 2)
            j = half_len - i
            print("i : %d, j : %d "%(i,j))
            
            if i < m and B[j-1] > A[i]:
                print("A[i] : %d, B[j-1] : %d "%(A[i],B[j-1]))
                # i is too small, must increase it
                imin = i + 1
            elif i > 0 and A[i-1] > B[j]:
                print("A[i-1] : %d, B[j] : %d "%(A[i-1],B[j]))
                # i is too big, must decrease it
                imax = i - 1
            else:
                # i is perfect

                if i == 0: max_of_left = B[j-1]
                elif j == 0: max_of_left = A[i-1]
                else: max_of_left = max(A[i-1], B[j-1])
                print("max_of_left : ",max_of_left)

                if (m + n) % 2 == 1:
                    print("(m + n) % 2 == 1 , max_of_left : ",max_of_left)
                    return max_of_left

                if i == m: min_of_right = B[j]
                elif j == n: min_of_right = A[i]
                else: min_of_right = min(A[i], B[j])
                print("min_of_right : ",min_of_right)
                
                return (max_of_left + min_of_right) / 2.0
思路二:转化为求第K小的值

首先转成求A和B数组中第k小(两数组长度和的一半)的数的问题, 然后用k/2在A和B中分别找。

比如k = 6(n=12 or n=13), 分别看A和B中的第3个数, 已知 A1 < A2 < A3 < A4 < A5… 和 B1 < B2 < B3 < B4 < B5…。如果A3 <= B3, 那么第6小的数肯定不会是A1, A2, A3, 因为最多有两个数小于A1(可能是B1<B2<A1), 三个数小于A2(可能是A1<B1<B2<A2), 四个数小于A3(可能是A1<A2<B1<B2<A3)。 关键点是从 k/2 开始来找。

B3至少大于5个数, 所以第6小的数有可能是B1 (A1 < A2 < A3 < A4 < A5 < B1), 有可能是B2 (A1 < A2 < A3 < B1 < A4 < B2), 有可能是B3 (A1 < A2 < A3 < B1 < B2 < B3)。而B3后面的因为至少大于6个数,所以肯定不会是第6小的数了。那就可以排除掉A1, A2, A3, 转成求A4, A5, … B1, B2, B3, …这些数中第3小的数的问题, k就被减半了。每次都假设A的元素个数少, pa = min(k/2, lenA)的结果可能导致k == 1或A空, 这两种情况都是终止条件。

发问,为什么要从k/2开始寻找,依旧k = 6, 我可以比较A1 和 B5的关系么,可以这样做,但是明显的问题出现在如果A1 > B5,那么这个第6小的数应该存在于B6和A1中。

如果A1 < B5,这个时间可能性就很多了,比如A1 < A2 < A3 < A4 < B1 < B2,各种可能,无法排除元素,所以还是要从k/2开始寻找。

Python 代码实现

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        # k:A,B两数组中第k大的数
        def findKth(A, B, k):
            if len(A) == 0:
                return B[k-1]
            if len(B) == 0:
                return A[k-1]
            if k == 1:
                return min(A[0], B[0])

            a = A[k // 2 - 1] if len(A) >= k // 2 else None
            b = B[k // 2 - 1] if len(B) >= k // 2 else None

            if b is None or (a is not None and a < b):
                return findKth(A[k // 2:], B, k - k // 2)
            else:
                return findKth(A, B[k // 2:], k - k // 2)  # 这里要注意:因为 k/2 不一定 等于 (k - k/2)
            
        n = len(nums1) + len(nums2)
        if n % 2 == 1:
            return findKth(nums1, nums2, n // 2 + 1)
        else:
            # 偶数的情况要找到中间两个数,然后求均值。
            smaller = findKth(nums1, nums2, n // 2)
            bigger = findKth(nums1, nums2, n // 2 + 1)
            return (smaller + bigger) / 2.0

THE END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值