• 4. Median of Two Sorted Arrays(topK-logk)


    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)).
    
    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
    
    

    解析

    • 题目是这样的:给定两个已经排序好的数组(可能为空),找到两者所有元素中第k大的元素。另外一种更加具体的形式是,找到所有元素的中位数。本篇文章我们只讨论更加一般性的问题:如何找到两个数组中第k大的元素?不过,测试是用的两个数组的中位数的题目,Leetcode第4题 Median of Two Sorted Arrays

    • 方案1:假设两个数组总共有n个元素,那么显然我们有用O(n)时间和O(n)空间的方法:用merge sort的思路排序,排序好的数组取出下标为k-1的元素就是我们需要的答案。
      这个方法比较容易想到,但是有没有更好的方法呢?

    • 方案2:我们可以发现,现在我们是不需要“排序”这么复杂的操作的,因为我们仅仅需要第k大的元素。我们可以用一个计数器,记录当前已经找到第m大的元素了。同时我们使用两个指针pA和pB,分别指向A和B数组的第一个元素。使用类似于merge sort的原理,如果数组A当前元素小,那么pA++,同时m++。如果数组B当前元素小,那么pB++,同时m++。最终当m等于k的时候,就得到了我们的答案——O(k)时间,O(1)空间。

    • 但是,当k很接近于n的时候,这个方法还是很费时间的。当然,我们可以判断一下,如果k比n/2大的话,我们可以从最大的元素开始找。但是如果我们要找所有元素的中位数呢?时间还是O(n/2)=O(n)的。有没有更好的方案呢?

     求中位数,给了两个例子。总结来看就是总数是偶数还是奇数。
    奇数:(m+n)/2求得中间数,它是第(m+n)/2+1个数。这个值在我们利用归并思想解题时使用。
    偶数:(m+n)/2、(m+n)/2+1。这两个数也就是第(m+n)/2、(m+n)/2+1个数。
    利用归并思想查找到第k个数,按照运算规则即可。
     double findK(vector<int>&a,int lena,vector<int>&b,int lenb,int k)
        {
            int i=0,j=0;
            for(;i<lena&&j<lenb;)
            {
                k--;
                if(a[i]<b[j])
                {
                    if(k==0)
                    return a[i];
                    i++;
                }
                else if(k==0)
                return b[j];
                else
                j++;
            }
            return i>=lena?b[j+k-1]:a[i+k-1];
        }
        double findMedianSortedArrays(vector<int>&nums1, vector<int>&nums2) {
            int m=nums1.size(),n=nums2.size();
            return ((m+n)&1)?findK(nums1,m,nums2,n,(m+n+1)>>1):
            ((findK(nums1,m,nums2,n,(m+n)>>1)+findK(nums1,m,nums2,n,((m+n)>>1)+1))*0.5);
        }
    
    • 我们可以考虑从k入手。如果我们每次都能够剔除一个一定在第k大元素之前的元素,那么我们需要进行k次。但是如果每次我们都剔除一半呢?所以用这种类似于二分的思想
    题目中需要求出的结果是中位数,中位数的特点是其以后的数都比它大,前面的数都比它小。又因为两个数组都已经是有序数组,因为我们所需要的结果就是数组a中的第i个元素和数组b中第j个元素,使得i+j-2等于两个数组长度和的一半,所以此题就可以转换成求i,j这两个值的问题了。在数组a中确定i以及在数组b中确定j,此时可以采用二分查找的方法,通过不断缩小查找范围来确实所需要查找的值,也符合题目中所要求的分治算法的思想。
    
    class Solution {  
    public:  
        int getkth(int s[], int m, int l[], int n, int k){  
            //确保m < n   
            if (m > n)   
                return getkth(l, n, s, m, k);  
            if (m == 0)  
                return l[k - 1];  
            if (k == 1)  
                return min(s[0], l[0]);  
        //递归过程  
            int i = min(m, k / 2), j = min(n, k / 2);  
            if (s[i - 1] > l[j - 1])  
                return getkth(s, m, l + j, n - j, k - j);  
            else  
                return getkth(s + i, m - i, l, n, k - i);  
            return 0;  
        }  
          
        double findMedianSortedArrays(int A[], int m, int B[], int n) {  
            //总长度的一半  
            int l = (m + n + 1) / 2;  
            int r = (m + n + 2) / 2;  
            return (getkth(A, m ,B, n, l) + getkth(A, m, B, n, r)) / 2.0;  
        }  
    };
    

    题目来源

  • 相关阅读:
    Java SE Development Kit Documentation
    java项目中, mybatis的sql XML文件,在写sql语句时,大于号小于号转义
    java 操作POI参考文章
    java 复制文件
    mysql to sql sersver
    java se 6(jdk1.6) API手册下载地址
    IT编程培训,线上线下,孰优孰劣
    linux单机部署zk集群
    6、定义告警媒介
    5、创建触发器
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/8283317.html
Copyright © 2020-2023  润新知