zoukankan      html  css  js  c++  java
  • 4. Median of Two Sorted Arrays(Array; Divide-and-Conquer)

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

    中位数:如果总数是偶数,那么中位数=中间两个数的平均数;如果总数是奇数,那么中位数=中间那个数的值

    思路: O(logx)的算法,就想到二分法。二分法结束的条件是任何一个array只剩下一个元素了。每次递归(二分),去除某个array的一半。另外注意,每次二分至少要去掉一个元素。

    class Solution {
    public:
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            int size1 = nums1.size();
            int size2 = nums2.size();
            int size = size1 + size2;
            int m = size >> 1;
            
            if(nums1.empty()){
                if(size%2 == 1) return nums2[m];
                else return (double) (nums2[m-1] + nums2[m])/2;
            } 
            if(nums2.empty()){
                if(size%2 == 1) return nums1[m];
                else return (double) (nums1[m-1] + nums1[m])/2;
            } 
            
            if(size%2 == 1) return findK(nums1, nums2, 0, size1-1, 0, size2-1, m);
            else return (double)(findK(nums1, nums2, 0, size1-1, 0, size2-1, m-1)+findK(nums1, nums2, 0, size1-1, 0, size2-1, m))/2;
        }
        
        int findK(vector<int>& nums1, vector<int>& nums2,int s1, int e1, int s2, int e2, int k){
            if(s1 == e1){
                if(k == 0) return min(nums1[s1],nums2[s2]); //为了防止s2+k-1越界
                if(nums1[s1] < nums2[s2+k-1]) return nums2[s2+k-1];
                else if(s2+k-1 == e2) return nums1[s1]; //为了防止s2+k越界
                else return min(nums1[s1], nums2[s2+k]);
            }
            if(s2 == e2){
                if(k == 0) return min(nums1[s1],nums2[s2]); //为了防止s1+k-1越界
                if(nums2[s2] < nums1[s1+k]) return max(nums2[s2],nums1[s1+k-1]);
                else if(s1+k-1 == e1) return nums2[s2]; //为了防止s1+k越界
                else return min(nums2[s2], nums1[s1+k]);
            }
            
            int m1 = s1+((e1-s1)>>1);
            int m2 = s2+((e2-s2)>>1);
            
            int halfLen = (e1 - s1 + e2 - s2 + 1) >> 1; 
            if(k > halfLen){ //k is in the second half
                if(nums1[m1] < nums2[m2]){ //delete first half of num1
                    return findK(nums1, nums2, m1+1, e1, s2, e2, k-(m1-s1+1)); //+1是考虑到m1==s1的情况,注意每次二分至少要去除一个元素
                }
                else{ //delete fist half of num2
                    return findK(nums1, nums2, s1, e1, m2+1, e2, k-(m2-s2+1));//+1是考虑到m2==s2的情况,注意每次二分至少要去除一个元素
                }
            }
            else{ //k is in the first half
                if(nums1[m1] < nums2[m2]){ //delete second half of num2
                    return findK(nums1, nums2, s1, e1, s2, m2, k);
                }
                else{ //delete second half of num1
                    return findK(nums1, nums2, s1, m1, s2, e2, k);
                }
            }
        }
    };

     改进:每次去掉(size1+size2)/2个元素。

    假设数组A和B如下,k=6,那么令i=k/2, j =k-k/2

    注意: j =k-k/2,保证i+j涵盖整个数组,否则测试用例 [1,2,6] [3,4,5,7,8],k=5的时候将会选取4和6,而不是4和5,原因是在某次比较A[1]和B[1](只有4个,k=5少了一个),选取了A的right subarray[2,6]和B的left subarray[3,4],漏选了Target元素5。如果使用j=k-k/2,那么将会比较A[1]和B[2](5个),从而也会保留B[2]。

    B的前三个元素可去掉比较好理解,那么为什么A的后5个元素也能取掉呢?

    =>即使B的后7个都比A的前三个大,B的前三个+A的前三个也已经满足k个要求,不需要A的后5个元素了。

    class Solution {
    public:
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            int len = nums1.size() + nums2.size();
            
            //see out to check null array
            if(nums1.empty()){
                if(len%2 == 1) return nums2[(len >> 1)];
                else return (double) (nums2[(len >> 1)-1] + nums2[(len >> 1)])/2;
            } 
            if(nums2.empty()){
                if(len%2 == 1) return nums1[(len >> 1)];
                else return (double) (nums1[(len >> 1)-1] + nums1[(len >> 1)])/2;
            } 
    
    
            if( len%2 == 1) return findK(nums1,0,nums1.size()-1, nums2, 0, nums2.size()-1,(len >> 1));
            else {
                int m1 = findK(nums1,0,nums1.size()-1, nums2, 0, nums2.size()-1,(len >> 1)-1);
                int m2 = findK(nums1,0,nums1.size()-1, nums2, 0, nums2.size()-1,(len >> 1));
                return (double) (m1+m2)/2;
            }
            
        }
        
        int findK(vector<int>& nums1,int s1,int e1, vector<int>& nums2, int s2, int e2, int k) {
            //termination
            if(k==0) return min(nums1[s1],nums2[s2]);
            if(s1==e1 && s2 == e2) {
                return max(nums1[s1],nums2[s2]);
            }
            if(s1 == e1){ // only one element in nums1
                if(s2+k > e2){ //prevent overflow 
                    return max(nums1[s1],nums2[e2]);
                }
                else if(nums1[s1] < nums2[s2+k-1]) return nums2[s2+k-1];
                else if(nums1[s1] < nums2[s2+k]) return nums1[s1];
                else return nums2[s2+k];
            }
            else if(s2 == e2){// only one element in nums2
                if(s1+k > e1){ //prevent overflow 
                    return max(nums1[e1],nums2[s2]);
                }
                else if( nums2[s2] < nums1[s1+k-1]) return nums1[s1+k-1];
                else if(nums2[s2] < nums1[s1+k]) return nums2[s2];
                else return nums1[s1+k];   
            }
            
            //make the length of first half of m1 + first half of m2  =  k
            int m1 = s1 + (k >> 1); 
            if(m1 > e1){ //check overflow
                m1 = e1;        
            }
            int m2 = s2 + k - (m1-s1+1); 
            if(m2 > e2){ //check overflow
                m2 = e2;
                m1 = s1 + k - (m2-s2+1); 
            }
            
            if((m1 == s1 && m2 == e2) || (m1==e1 && m2==s2)){ 
                //try to make k-1
                if(nums1[s1] < nums2[s2]) return findK(nums1,s1+1,e1,nums2,s2,e2,k-1); 
                else return findK(nums1,s1,e1,nums2,s2+1,e2,k-1); 
            }
    
            //compare two arrays
            if(nums1[m1]<nums2[m2]){ //remove first half of num1 and second half of num2
                return findK(nums1,m1,e1,nums2,s2,m2,k-(m1-s1)); //need to guarantee ! (m1==s1 && m2==e2)
            }
            else{//remove first half of num2 and second half of num1
                return findK(nums1,s1,m1,nums2,m2,e2,k-(m2-s2)); // need to guarantee ! (m1==e1 && m2==s2)
            }
        }
        
    };

     

  • 相关阅读:
    Android 跳转到系统应用管理
    Android权限管理PermissionsDispatcher2.3.2使用+原生6.0权限使用
    Android权限管理PermissionsDispatcher2.3.2使用+原生6.0权限使用
    Android 6.0 Permission权限与安全机制
    Windows下Mongodb安装及配置
    mongo 3.0 备份和还原数据库 ,及too many positional arguments错误
    maven 将jar 下载到工程当前目录下
    MyBatis两张表字段名相同产生的问题
    svn报错can only be performed on a version resource [at this time].
    angular之interceptors拦截器
  • 原文地址:https://www.cnblogs.com/qionglouyuyu/p/4641096.html
Copyright © 2011-2022 走看看