zoukankan      html  css  js  c++  java
  • 寻找两个有序数组的中位数

    题目描述:
    给定两个大小为 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. $len(left_part) = len(right_part)$
    2. $max(left_part)le min(right_part)$

    那么,我们已经将{A, B}中的所有元素划分为相同长度的两个部分,且其中一部分的元素总是大于另一部分的元素。那么:
    $median = frac{max(left_part)+min(right_part)}{2}$
    确保这两个条件,我们只需要保证:

    1. $i+j = m-i+n-j$(或:($m-i+n-j+1$))如果$n ge m$,只需要使$i = 0 sim m,j=frac{m+n+1}{2}-i$
    2. $B[j-1] le A [i] 以及 A[i-1] le B[j]$

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

    1.设$imin=0, imax=m$,然后开始在$left|{imin, imax} ight|$中进行搜索。
    2.令$i = frac{imin+imax}{2}, j =frac{m+n+1}{2} - i$
    3.现在我们有$len(left_part)=len(right_part)$.我们会遇到三种情况:

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

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

    $max(A{i-1],B[j-1]})$,当$m+n$为奇数时

    $frac{max(A[i-1],B[j-1])+min(A[i],B[j])}{2}$,当$m+n$为偶数时

    考虑临界值。$i=0, i=m, j=0,j=n$。此时,$A[i-1], B[j-1], A[i], B[j]$可能不存在。
    确保$max(left_part)le min(right_part)$。如果$i$和$j$不是临界值,必须同时检查$B[j-1]le A[i]$以及$A[i-1] le B[j]$是否成立。但是如果$A[i-1], B[j-1], A[i], B[j]$中部分不存在,我们只需要检查两个条件中的一个(或不需要检查)

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

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

    1.($j=0$ or $i=m$ or $B[j-1]le A[i]$) 或是 ($i=0$ or $j=n$ or $A[i-1]le B[j]$)这说明$i$是完美的,可以停止搜索。
    2.$j>0$ and $i < m$ and $B[j-1] >A[i]$这意味着$i$太小,必须增大它。
    3.$i>0$ and $j < n$ and $A[i-1]>B[j]$这意味着$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
    
  • 相关阅读:
    装饰器
    目录和文件操作
    网络通信过程
    epoll并发
    laravel(包含lumen)框架中的跨域函数实例
    windows使用nginx
    nginx反向代理配置 其实很简单
    前端html页面使用marked点亮你的代码
    PHPWAMP开启SSL,PHPWAMP配置ssl证书
    php接收并存储base64位字符串图片
  • 原文地址:https://www.cnblogs.com/CZT-TS/p/10241637.html
Copyright © 2011-2022 走看看