• LeetCode 4: Median of Two Sorted Arrays


    Description:

    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

    描述:

    两个有序数组nums1和nums2,数组元素数量分别为m和n。

    寻找两个数组的中位数。要求程序的时间复杂度为O(lg(m+n))。

    假设数组nums1和nums2不同时为空。

    示例1:

      nums1 = [1, 3]

      nums2 = [2]

      中位数为2.0

    示例2:

      nums1 = [1, 2]

      nums2 = [3, 4]

      中位数为(2 + 3) / 2 = 2.5

    方法:

    首先,我们先理解中位数的概念和意义。中位数,又称中点数,中值。中数是按顺序排列的一组数据中居于中间位置的数,即在这组数据中,有一半的数据比他大,有一半的数据比他小。对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数。

    中位数的意义是把一个集合分为两个长度相等的子集合,其中一个子集合总是比另外一个集合大。

    假设题中两个数组nums1和nums2分别以集合A和B表示。

    首先,在随机位置i把集合A分成两个子集合。

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

    由于集合A的大小为m,因此共有(m+1)中划分方法(i = 0 ~ m)。

    子集合left_A的长度为i,子集合right_A的长度为m - i。注意,当i=0时,left_A为空,当i=m时,right_A为空。

    同样地,在随机位置j将集合B分为两个子集合。

            left_B          |           right_B
    B[0], B[1], ..., B[j-1] | B[i], B[i+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[i], B[i+1], ..., B[n - 1]

    如果可以保证:

    len(left_part)=len(right_part)
    max(left_part) ≤ min(right_part)

    那么,我们将集合A和集合B分割为两个长度相等的部分,并且left_part总是小于right_part。

    并且:

    median= (max(left_part)+min(right_part))/2

    为了保证上述条件成立,我们需要保证:

    1. i+j=m−i+n−j (or: m - i + n - j + 1)
       if n≥m, we just need to set:  i=0∼m, j=(m+n+1)/2−i
    
    2. B[j−1]≤A[i] and A[i−1]≤B[j]

    PS1: 为了便于表述,假设A[i-1]、B[j-1]、A[i]和B[j]有效,即使i=0,i=m,j=0和j=n时。后面将阐述如何处理这些情况。

    PS2: 为什么要求n>=m?主要是确保j的值非负。由于0im,并且j = (m + n + 1)/2- i。如果n<m, 那么j的值可能为负,导致结果错误。

    综上所述,整体思路是:

    在区间[0,m]中寻找i的值,使得

    B[j−1]≤A[i] and A[i−1]≤B[j],  这里, j = (m + n + 1)/2 - i

    可以使用二叉查找的方式查询满足上述条件的i值。

    1. 设置imin=0, imax=m,并在[imin,imax]区间搜索;
    2. 设置i=(imin + imax)/2, j = (m + n + 1)/2 - i;
    3. 此时,len(left_part) = len(right_part)。并且会有如何三种情形。
        a. B[j - 1] <= A[i]且A[i-1] <= B[j]。此时,我们找到正确的结果,停止搜索并退出。
        b. B[j - 1] > A[i]。此时,A[i]的值较小,需要调整i的值使得B[j-1]<=A[i]。增加i的值,导致A[i]的值增加,并且j的值减小,B[j-1]的值也相应减小。开始搜索区间[i + 1, imax]。设置imin的值为i+1,跳转到步骤2。
        c. A[i - 1] > B[j]。此时,以为这A[i-1]的值较大,需要减少i的值,并开始搜索区间[imin, i - 1]。设置imax的值为i-1,并跳转到步骤2。

    当寻找到满足上述条件的i值后,中间值的计算方式如下:

    max(A[i−1],B[j−1]),  当m + n为奇数时​;
    ​(max(A[i−1],B[j−1])+min(A[i],B[j])),当n为偶数时。

    现在,我们开始考虑边际条件。即i=0或i=m或j=0或j=n时,此时A[i-1]、A[i]、B[j-1]或B[j]的值可能并不存在。

    我们需要保证max(A[i−1],B[j−1])<=min(A[i],B[j])。所以当i和j的值均不是边际值时,需要检查B[j-1]<=A[i]且A[i-1]<=B[j]。

    如果i或j的值为边际值,那么我们不需要检查相应的边际条件。例如, 如果 i=0, 那么A[i1]不存在。此时,我们不需要检查A[i1]B[j];我们需要做的是:

    在区间[0,m]中搜索i的值使得
    (j=0或i = m或B[j−1]≤A[i])并且
    (i=0或j = n或A[i−1]≤B[j])

    在每次搜索循环中,我们遇到以下三种情形:

    1. (j=0或i=m或B[j−1]≤A[i]) 并且(i=0或j=n或A[i−1]≤B[j]) 
       表明i为所需要寻找的值,停止搜索。
    2. j>0且i<m且B[j−1]>A[i] 
        表明i的值较小,增加i的值
    3. i>0且j<n且A[i−1]>B[j] 
        表明i的值较大,减少i的值

    此外,由于i<mj>0且i>0j<n。所以在情形2和情形3下我们不需要检查j>0和i>0的条件。

    class Solution {
    public:
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            int m = nums1.size();
            int n = nums2.size();
            if(m > n) {
                vector<int> temp = nums1;
                nums1 = nums2;
                nums2 = temp;
                int t = m;
                m = n;
                n = t;
            }
            
            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 && nums2[j - 1] > nums1[i]){
                    iMin = i + 1;
                } else if(i > iMin && nums1[i - 1] > nums2[j]) {
                    iMax = i - 1;
                } else {
                    int maxLeft = 0;
                    if(i == 0) maxLeft = nums2[j - 1];
                    else if(j == 0) maxLeft = nums1[i - 1];
                    else maxLeft = max(nums1[i - 1], nums2[j - 1]);
                    if((m + n) % 2 != 0) return maxLeft;
                    
                    int minRight = 0;
                    if(i == m) minRight = nums2[j];
                    else if(j == n) minRight = nums1[i];
                    else minRight = min(nums1[i], nums2[j]);
                    
                    return ((double)minRight + maxLeft) / 2.0;
                }
            }
            return 0.0;
        }
    };

    本方法的时间复杂度为O(log(min(m,n)),空间复杂度为O(1)。

  • 相关阅读:
    Nutch的配置(使用MySQL作为数据存储)
    MySQL简单实现多字段模糊查询
    nutch的一些基础整理
    Java分布式爬虫Nutch教程——导入Nutch工程,执行完整爬取
    Nutch2 WebPage写入数据库的过程分析
    Nutch2 WebPage 字段解释
    nutch如何修改regex-urlfilter.txt爬取符合条件的链接
    Run Nutch In Eclipse on Linux and Windows nutch version 0.9
    Linux Mint 17.1 安装全配置
    Ubuntu(Linux Mint):sudo apt-get upgrade升级失败
  • 原文地址:https://www.cnblogs.com/alpaca/p/9475174.html
Copyright © 2020-2023  润新知