[leetcode] 4-尋找兩個有序數組的中位數

給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。算法

請你找出這兩個有序數組的中位數,而且要求算法的時間複雜度爲 O(log(m + n))。數組

你能夠假設 nums1 和 nums2 不會同時爲空。ui

Input: nums1 = [1, 3]
nums2 = [2]指針

Output: 則中位數是 2.0code

2.思路

1.外排
因爲數組是有序的,所以能夠用外排,將兩個數組marge成另外的數組help[]。從有序數組help中找出中位數就是一件簡單的事了。(缺點是須要額外的空間來構造一個有序的新數組。)遞歸

實際時間複雜度爲O(m+n),空間複雜度爲O(m+n)。leetcode

2.雙指針法
定義兩個指針分別指向兩個數組的開頭。若數組總數num爲奇數,則查找第num/2個數;若總數爲偶數,則找那兩個/2.
(這裏不提供代碼)get

時間複雜度O(m+n),空間複雜度O(1)。源碼

3. 二分法查找
通常時間複雜度爲O(logn)的算法,都是須要用到分治思想(且通常爲二分)。
兩個有序數組求中位數,問題通常化爲,求兩個有序數組的第k個數,當k = (m+n)/2時爲原問題的解。
怎麼求第k個數?分別求出第一個和第二個數組的第 k / 2個數 a 和 b,而後比較 a 和 b,當a < b ,說明第 k 個數位於 a數組的第 k / 2個數後半段,或者b數組的 第 k / 2 個數前半段,問題規模縮小了一半,而後遞歸處理就行。io

時間複雜度O(log m+n),空間複雜度O(1)

源碼來源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/zhen-zheng-ologmnde-jie-fa-na-xie-shuo-gui-bing-pa/

3.題解

外排法

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
       int m=nums1.length;
       int n=nums2.length;
       int i=0;
       int j=0;
       int k=0;
       int[] help=new int[n+m];
       while(i<=m-1&&j<=n-1){
           help[k++]=nums1[i]<=nums2[j]?nums1[i++]:nums2[j++];
       }
       while(i<m){
           help[k++]=nums1[i++];
       }
       while(j<n){
           help[k++]=nums2[j++];
       }
        k=help.length;
        if(k%2==0){
            return (help[k/2]+help[k/2-1])/2.0;
        }
        else{
            return help[k/2]*1.0;
        }

    }
}

二分查找法

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        //處理任何一個nums爲空數組的狀況
        if (m == 0) {
            if (n % 2 != 0)
                return 1.0 * nums2[n / 2];
            return (nums2[n / 2] + nums2[n / 2 - 1]) / 2.0;
        }
        if (n == 0) {
            if (m % 2 != 0)
                return 1.0 * nums1[m / 2];
            return (nums1[m / 2] + nums1[m / 2 - 1]) / 2.0;
        }
        int total = m + n;
        //總數爲奇數,找第 total / 2 + 1 個數
        if ((total & 1) == 1) {
            return find_kth(nums1, 0, nums2, 0, total / 2 + 1);
        }
        //總數爲偶數,找第 total / 2 個數和第total / 2 + 1個數的平均值
        return (find_kth(nums1, 0, nums2, 0, total / 2) + find_kth(nums1, 0, nums2, 0, total / 2 + 1)) / 2.0;

    }

    //尋找a 和 b 數組中,第k個數字
    double find_kth(int[] a, int a_begin, int[] b, int b_begin, int k) {
        //當a 或 b 超過數組長度,則第k個數爲另一個數組第k個數
        if (a_begin >= a.length)
            return b[b_begin + k - 1];
        if (b_begin >= b.length)
            return a[a_begin + k - 1];
        //k爲1時,兩數組最小的那個爲第一個數
        if (k == 1)
            return Math.min(a[a_begin], b[b_begin]);

        int mid_a = Integer.MAX_VALUE;
        int mid_b = Integer.MAX_VALUE;
        //mid_a / mid_b 分別表示 a數組、b數組中第 k / 2 個數
        if (a_begin + k / 2 - 1 < a.length)
            mid_a = a[a_begin + k / 2 - 1];
        if (b_begin + k / 2 - 1 < b.length)
            mid_b = b[b_begin + k / 2 - 1];
        //若是a數組的第 k / 2 個數小於b數組的第 k / 2 個數,表示總的第 k 個數位於 a的第k / 2個數的後半段,或者是b的第 k / 2個數的前半段
        //因爲範圍縮小了 k / 2 個數,此時總的第 k 個數實際上等於新的範圍內的第 k - k / 2個數,依次遞歸
        if (mid_a < mid_b)
            return find_kth(a, a_begin + k / 2, b, b_begin, k - k / 2);
        //不然相反
        return find_kth(a, a_begin, b, b_begin + k / 2, k - k / 2);
    }
}
相關文章
相關標籤/搜索