1. 程式人生 > 其它 >[LeetCode]4.尋找兩個正序陣列的中位數(Java)

[LeetCode]4.尋找兩個正序陣列的中位數(Java)

LeetCode 04

原題地址: median-of-two-sorted-arrays

題目描述:

示例 1:
輸入:nums1 = [1,3], nums2 = [2]
輸出:2.00000
解釋:合併陣列 = [1,2,3] ,中位數 2

示例 2:
輸入:nums1 = [1,2], nums2 = [3,4]
輸出:2.50000
解釋:合併陣列 = [1,2,3,4] ,中位數 (2 + 3) / 2 = 2.5

示例 3:
輸入:nums1 = [0,0], nums2 = [0,0]
輸出:0.00000

提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

進階:你能設計一個時間複雜度為 O(log (m+n)) 的演算法解決此問題嗎?

解答方法:

1.nums1,nums2合併後排序

時間複雜度:遍歷全部陣列 O(m+n)
空間複雜度:開闢了一個數組,儲存合併後的兩個陣列 O(m+n)

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] res=new int[nums1.length + nums2.length];
        int n = 0;
        int len = nums1.length + nums2.length;
        for (int i = 0; i < nums1.length; i++){
            res[i] = nums1[i];
        }
        for (int i = nums1.length; i < res.length; i++){
            res[i] = nums2[n];
            n++;
        }
        Arrays.sort(res);
        if(len % 2 == 0){
            return (double)(res[len/2] + res[len/2 - 1])/2;
        }else{
            return res[len/2];
        }
    }
}

問題:

  • 拷貝產生新的陣列從而增加時間複雜度,而題目限制了時間複雜度為 O(log (m+n)),沒達到要求。

2.二分法

用到二分的方法才能達到 O(log(m+n))
分別找第 (m+n+1) / 2 個,和 (m+n+2) / 2 個,然後求其平均值即可,對奇偶數均適用。
由於數列是有序的,其實我們完全可以一半兒一半兒的排除。假設我們要找第 k 小數,我們可以每次迴圈排除掉 k/2 個數。

class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { 
            return findMedianSortedArrays(B,A); // 保證 m <= n
        }
        int iMin = 0, iMax = m;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = (m + n + 1) / 2 - i;
            if (j != 0 && i != m && B[j-1] > A[i]){ // i 需要增大
                iMin = i + 1; 
            }
            else if (i != 0 && j != n && A[i-1] > B[j]) { // i 需要減小
                iMax = i - 1; 
            }
            else { // 達到要求,並且將邊界條件列出來單獨考慮
                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; } // 奇數的話不需要考慮右半部分

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