寻找两个有序数组的中位数

题目描述:
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
链接https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/

示例 1:

nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5

思路:(参考官方题解)
由题目可知,给定两个有序数组,假设分别为数组A,数组B。
在任一位置将数组A划分成两个部分

      left_A       |      right_A
A[0], A[1], …, A[i-1] | A[i], A[i+1], …, A[m-1]

同理在任一位置将数组B划分成两个部分:

     left_B        |       right_B
B[0], B[1], …, B[j-1] | B[j], B[j+1], …, B[n-1]

将left_A和left_B放入一个集合,并将right_A和right_B放入另一个集合。再把这两个新的集合分别命名为left_part和right_part:

    left_part      |     right_part
A[0], A[1], …, A[i-1] | A[i], A[i+1], …, A[m-1]
B[0], B[1], …, B[j-1] | B[j], B[j+1], …, B[n-1]

如果我们可以确认:

1.  l e n ( l e f t _ p a r t ) = l e n ( r i g h t _ p a r t ) len(left\_part) = len(right\_part) len(left_part)=len(right_part)
2.  m a x ( l e f t _ p a r t ) ≤ m i n ( r i g h t _ p a r t ) max(left\_part)\le min(right\_part) max(left_part)min(right_part)

那么,我们已经将{A, B}中的所有元素划分为相同长度的两个部分,且其中一部分的元素总是大于另一部分的元素。那么:
m e d i a n = m a x ( l e f t _ p a r t ) + m i n ( r i g h t _ p a r t ) 2 median = \frac{max(left\_part)+min(right\_part)}{2} median=2max(left_part)+min(right_part)
确保这两个条件,我们只需要保证:

1.  i + j = m − i + n − j i+j = m-i+n-j i+j=mi+nj(或:( m − i + n − j + 1 m-i+n-j+1 mi+nj+1))如果 n ≥ m n \ge m nm,只需要使 i = 0 ∼ m , j = m + n + 1 2 − i i = 0 \sim m,j=\frac{m+n+1}{2}-i i=0mj=2m+n+1i
2.  B [ j − 1 ] ≤ A [ i ] 以 及 A [ i − 1 ] ≤ B [ j ] B[j-1] \le A [i] 以及 A[i-1] \le B[j] B[j1]A[i]A[i1]B[j]

接着,按照以下步骤进行二叉树搜索:

1.设 i m i n = 0 , i m a x = m imin=0, imax=m imin=0,imax=m,然后开始在 ∣ i m i n , i m a x ∣ \left|{imin, imax}\right| imin,imax中进行搜索。
2.令 i = i m i n + i m a x 2 , j = m + n + 1 2 − i i = \frac{imin+imax}{2}, j =\frac{m+n+1}{2} - i i=2imin+imax,j=2m+n+1i
3.现在我们有 l e n ( l e f t _ p a r t ) = l e n ( r i g h t _ p a r t ) len(left\_part)=len(right\_part) len(left_part)=len(right_part).我们会遇到三种情况:

  • B [ j − 1 ] ∣ ≤ A [ i ] B[j - 1]| \le A[i] B[j1]A[i] A [ i − 1 ] ≤ B [ j ] A[i-1]\le B[j] A[i1]B[j]
    这意味着我们找到了目标对象 i i i,所以可以停止搜索。
  • B [ j − 1 ] > A [ i ] B[j-1] > A[i] B[j1]>A[i]
    这意味着 A [ i ] A[i] A[i]太小,我们必须调整 i i i以使 B [ j − 1 ] ≤ A [ i ] B[j-1] \le A[i] B[j1]A[i]
    i i i j j j的关系可知, i i i增大的时候, j j j就会减小。所以此处必须增大 i i i,将搜索范围调整为 [ i + 1 , i m a x ] [i + 1, imax] [i+1,imax]。因此 i m i n = i + 1 imin=i+1 imin=i+1,并转向步骤2。
  • A [ i − 1 ] > B [ j ] A[i-1]>B[j] A[i1]>B[j]。这说明 A [ i − 1 ] A[i-1] A[i1]太大,我们必须减小 i i i以使 A [ i − 1 ] ≤ B [ j ] A[i - 1]\le B[j] A[i1]B[j]。也就是说,我们必须将搜索范围调整为 [ i m i n , i − 1 ] [imin, i-1] [imin,i1]
    因此,着 i m a x = i − 1 imax=i-1 imax=i1,并转向步骤2.

当找到目标对象i时,中位数为:

m a x ( A i − 1 ] , B [ j − 1 ] ) max(A{i-1],B[j-1]}) max(Ai1],B[j1]),当 m + n m+n m+n为奇数时

m a x ( A [ i − 1 ] , B [ j − 1 ] ) + m i n ( A [ i ] , B [ j ] ) 2 \frac{max(A[i-1],B[j-1])+min(A[i],B[j])}{2} 2max(A[i1],B[j1])+min(A[i],B[j]),当 m + n m+n m+n为偶数时

考虑临界值。 i = 0 , i = m , j = 0 , j = n i=0, i=m, j=0,j=n i=0,i=m,j=0,j=n。此时, A [ i − 1 ] , B [ j − 1 ] , A [ i ] , B [ j ] A[i-1], B[j-1], A[i], B[j] A[i1],B[j1],A[i],B[j]可能不存在。
确保 m a x ( l e f t p a r t ) ≤ m i n ( r i g h t p a r t ) max(left_part)\le min(right_part) max(leftpart)min(rightpart)。如果 i i i j j j不是临界值,必须同时检查 B [ j − 1 ] ≤ A [ i ] B[j-1]\le A[i] B[j1]A[i]以及 A [ i − 1 ] ≤ B [ j ] A[i-1] \le B[j] A[i1]B[j]是否成立。但是如果 A [ i − 1 ] , B [ j − 1 ] , A [ i ] , B [ j ] A[i-1], B[j-1], A[i], B[j] A[i1],B[j1],A[i],B[j]中部分不存在,我们只需要检查两个条件中的一个(或不需要检查)

[ 0 , m ] [0, m] [0,m]中搜索目标对象 i i i,以使:( j = 0 j=0 j=0 or i = m i=m i=m or B [ j − 1 ] ≤ A [ i ] B[j-1]\le A[i] B[j1]A[i]) 或是 ( i = 0 i=0 i=0 or j = n j=n j=n or A [ i − 1 ] ≤ B [ j ] A[i-1]\le B[j] A[i1]B[j]),其中 j = m + n + 1 2 − i j=\frac{m+n+1}{2}-i j=2m+n+1i

循环搜索中,会遇到三种情况:

1.( j = 0 j=0 j=0 or i = m i=m i=m or B [ j − 1 ] ≤ A [ i ] B[j-1]\le A[i] B[j1]A[i]) 或是 ( i = 0 i=0 i=0 or j = n j=n j=n or A [ i − 1 ] ≤ B [ j ] A[i-1]\le B[j] A[i1]B[j])这说明 i i i是完美的,可以停止搜索。
2. j &gt; 0 j&gt;0 j>0 and i &lt; m i &lt; m i<m and B [ j − 1 ] &gt; A [ i ] B[j-1] &gt;A[i] B[j1]>A[i]这意味着 i i i太小,必须增大它。
3. i &gt; 0 i&gt;0 i>0 and j &lt; n j &lt; n j<n and A [ i − 1 ] &gt; B [ j ] A[i-1]&gt;B[j] A[i1]>B[j]这意味着 i i i太大,我们必须减小它。

JAVA版

class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            if (i < iMax && B[j-1] > A[i]){
                iMin = i + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = i - 1; // i is too big
            }
            else { // i is perfect
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }
}

Python版

def median(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, imax, half_len = 0, m, (m + n + 1) / 2
    while imin <= imax:
        i = (imin + imax) / 2
        j = half_len - i
        if i < m and B[j-1] > A[i]:
            # i is too small, must increase it
            imin = i + 1
        elif i > 0 and 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])

            if (m + n) % 2 == 1:
                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])

            return (max_of_left + min_of_right) / 2.0
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值