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)
            }
        }
        
    };

     

  • 相关阅读:
    Java 基础
    Java 数据类型
    Spring 拦截器实现事物
    SSH 配置日记
    Hibernate 知识提高
    Jsp、Servlet
    leetcode 97. Interleaving String
    leetcode 750. Number Of Corner Rectangles
    leetcode 748. Shortest Completing Word
    leetcode 746. Min Cost Climbing Stairs
  • 原文地址:https://www.cnblogs.com/qionglouyuyu/p/4641096.html
Copyright © 2011-2022 走看看