LeetCode(4) ---- Median of Two Sorted Arrays

1.Problem

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

2.Translation

給兩個各自排好序的數(shù)組,然后找出他們兩個中的中間值,如示例所示。然后給了時間復(fù)雜度的限制。

3.My View

出去開一個大會跑回來還有各種各樣的事要做……但是還是先刷一道算法吧。

回來室友說這個很簡單,然后做了n久,雖然有了想法,想法是合并->排序,說起來應(yīng)該達(dá)不到n方的復(fù)雜度,但是無從下手。

然后室友說用了Python的庫函數(shù),排序(數(shù)組1+數(shù)組2)。
雖然覺得直接調(diào)庫就沒啥意思了,但是還是寫了一個調(diào)庫的,更高端的有空再研究。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        //構(gòu)建新數(shù)組
         int[] nums = new int[nums1.length+nums2.length];
        //將數(shù)組合并(采用arraycopy函數(shù))
        if(nums1.length>0&&nums2.length>0){
         System.arraycopy(nums1, 0, nums, 0, nums1.length);
         System.arraycopy(nums2, 0, nums, nums1.length, nums2.length);
        }else if(nums1.length>0&&nums2.length==0){
           System.arraycopy(nums1, 0, nums, 0, nums1.length); 
        }else if(nums2.length>0&&nums1.length==0){
            System.arraycopy(nums2, 0, nums, 0, nums2.length); 
        }
        //將數(shù)組排序(sort函數(shù))
        Arrays.sort(nums);
        //返回結(jié)果
        return (nums[(nums.length-1)/2]+nums[nums.length/2])/2.0;
    }
}

這里主要用了arraycopy和sort函數(shù),用來完成數(shù)組合并和排序。

當(dāng)然,嗯,路過打個醬油啦!

于是抽空又寫了一個能說的過去的。
不過當(dāng)然不能跟大神比啦。

6KBM92FU9_L_W%1GUTI2JW.png

連大眾算法都沒上。

public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
                 //構(gòu)建新數(shù)組
             int[] nums = new int[nums1.length+nums2.length];
             int num1_len = nums1.length,num2_len = nums2.length;
             int i = 0,j = 0,k = 0;
                //調(diào)整數(shù)組訪問順序  
             if(num1_len > num2_len){
                 return findMedianSortedArrays(nums2,nums1);
             }      
            while(i<num1_len||j<num2_len){
                 //余數(shù)據(jù)處理  
             if(i<=nums1.length-1&&j>nums2.length-1){
                 nums[k] = nums1[i];
                 i++;
                 k++;
                 continue;
             } 
             if(i>nums1.length-1&&j<=nums2.length-1){
                 nums[k] = nums2[j];
                 j++;
                 k++;
                 continue;
             }  
                 //正常數(shù)據(jù)處理
             if(nums1[i]<=nums2[j]){
                 nums[k] = nums1[i];
                 i++;
             }else{
                 nums[k] = nums2[j];
                 j++;
             }   
             k++;
            }    
                 //結(jié)果
            return (nums[(nums.length-1)/2]+nums[nums.length/2])/2.0;
        }

期間也是遇到大大小小的錯誤,連續(xù)提交了幾次才成功。算法的理念就是排序合并,這個想法是源自于數(shù)據(jù)結(jié)構(gòu)鏈表合并排序的題目,以前沒仔細(xì)寫過,今天算是拿數(shù)組練練手了。

真正官方的,
NB的在下面。

Solution

Put left_A and left_B into one set, and put right_A and right_B into another set.

把A數(shù)組分成左右兩部分,B數(shù)組也分成左右兩部分。

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

然后如果我們確保

//左右長度一致
len(left_part)=len(right_part)
//左部分最大值小于右部分最小值
max(left_part)≤min(right_part)

那么我們就會很輕易地得到答案
a = (max(left_part)+ min(right_part))/2

那么接下來我們要解決的問題就是如何滿足這兩個條件

//首先我們要求(i是A數(shù)組左部分,j是B數(shù)組左部分,m是A的長度,
//n是B的長度,那么這樣很顯然就是讓A_left + B_left = A_right+B_right)
i+j=m?i+n?j 
//為了確保大小,我們結(jié)合剛開始給的表格來看
B[j?1]≤A[i] and A[i?1]≤B[j]

and then?

Searching i in [0,m], to find an object i such that:
//在【0,m】區(qū)間搜索一個滿足條件的i
B[j?1]≤A[i]  and A[i?1]≤B[j],  where j = (m+n+1)/2 - i

這里一定要確保j是非負(fù)數(shù),那么要求就是m要比n小,否則可能會因?yàn)閙/2太大導(dǎo)致j是負(fù)數(shù)。

同時我們在分析這種情況的時候,不能忽視了一些極端數(shù)據(jù),比如說空數(shù)組,重復(fù)數(shù)據(jù)等
官方給出的解釋是,當(dāng)我們比較這些情況的時候

B[j?1]≤A[i]  and A[i?1]≤B[j],  where j = (m+n+1)/2 - i

如果他們不存在(數(shù)據(jù)),可以直接空過去

那么在搜索的過程中就出現(xiàn)了三種情況

(j=0  or  i = m  or B[j?1]≤A[i]) and
i = 0 or j=n or A[i?1]≤B[j]) 
Means ii is perfect, we can stop searching.
(j > 0 and i <m and B[j?1]>A[i]) 
Means ii is too small, we must increase it.
(i>0 and j<n and A[i?1]>B[j]) 
Means ii is too big, we must decrease it.

最后是Code

 public double findMedianSortedArrays(int[] A, int[] B) {
        //獲取長度
        int m = A.length;
        int n = B.length;
        //確保長度m<n(當(dāng)然在這里我們也可以用遞歸來實(shí)現(xiàn),不過效率會低一點(diǎn))
        if (m > n) { 
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        //初始化變量
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        //循環(huán)檢查A數(shù)組
        while (iMin <= iMax) {
            //i是A數(shù)組中心
            int i = (iMin + iMax) / 2;
            //J也就是我們公式里的j
            int j = halfLen - i;
            //接下來就是我們的三種情況
            //通過調(diào)整imin和imax兩個值來確定i,j的位置,
            //也就是確保分片的合理性
            if (i < iMax && B[j-1] > A[i]){
                iMin = iMin + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = iMax - 1; // i is too big
            }
             //當(dāng)i是一個合適的切片點(diǎn)的時候,開始查找右片最小值和左片最大值
            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]); }
                //奇數(shù)個直接返回中心點(diǎn)
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

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

這個算法核心的地方還是在于分片。
同時這個算法也源自于高中的中值概念,通過排除最小最大值來得到中值。

更多優(yōu)秀算法建議去LeetCode查看。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容