[leetcode]4. median of two sorted arrays

第一个hard题。

我第一想法是合并排序,nlogn
对于这个题,时间复杂度应该是o(m+n)log(m+n),而不是题目要求的o(Log(m+n))

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    
     int i=0,j=0,k=0;
     int m=nums1.length;
     int n=nums2.length;
     int[] a=new int[m+n] ;
     
     for(i=0,j=0,k=0;i<m&&j<n;k++){
            if(nums1[i]<=nums2[j]){
                a[k]=nums1[i++];
            }
            else{
                a[k]=nums2[j++];
            }
        }
        if(j==n){
            while(i<m){
                a[k++]=nums1[i++];
            }
        }
        if(i==m){
            while(j<n){
                a[k++]=nums2[j++];
            }
        }
        
    int count=k;
    
    int mid=count/2;
    
    //特别要注意某一数组为空,另一数组只有一个,合并后数组只有一个元素的情形
    //加上mid>0的限制条件,否则mid-1会越界的
    if(count%2==0&&mid>0){
        return (a[mid-1]+a[mid])*0.5;
    }
    else
        return a[mid]*1.0;
    }
    
}

这是很经典的一道题目!!!

帮助我理解划分的思路:
https://blog.csdn.net/hk2291976/article/details/51107778
https://www.jianshu.com/p/9bd57fd52062

这道题是找中位数,扩展为找第中间个大的数。这样整个合并的数组就要分奇偶讨论。

长度为偶数要找第(len1+len2)/2大的数和第((len1+len2)/2 )+1大的数
长度为奇数,找第((len1+len2)/2 )+1 大的数

设p是nums1的第p大的数,q是nums2的第q大的数(q=k-p),这样讨论nums1[start1+p-1]和num2[start2+q-1]就能得到“合并”的第k大的数。

要求划分后nums1,nums2的左半部分都比nums1,nums2的右半部分要小,如果不行,就不停移动nums1的i来划分。

采用二分搜索算法,就是分治法中取2(其实取3,4,5,6都行,就是碰运气吗),取2的话最经典,时间复杂度是logn

class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // 强制规定nums1是短的那个
            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; //相当于取p,每次取p都是二分法
            int j = halfLen - i;  //相当于是q
            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; }   //合并数组长为奇数,就是 第(m + n + 1) / 2个大的数
               //合并数组长为偶数,就是 第(m + n + 1) / 2个大的数和第(m + n + 1) / 2  +1个大的数
                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;
    }
}

扩展找第k个大的数的化,就是分治的思想啦
https://www.jianshu.com/p/9bd57fd52062

猜你喜欢

转载自blog.csdn.net/weixin_36869329/article/details/83827464