【遞迴打卡1】在兩個長度相等的排序陣列中找到上中位數

帥地發表於2019-03-19

【題目】

給定兩個有序陣列arr1和arr2,已知兩個陣列的長度都為N,求兩個陣列中所有數的上中位數。要求時間複雜度O(logN),空間複雜度O(1)

【舉例】

例如 arr1 = [1, 2,3,4],arr2 = [3,4,5,6]。

總共8個數,則中位數就是第 4 小的數,為 3.

例如 arr1 = [0,1,2],arr2 = [3,4,5]。

總共6個數,則中位數就是第 3 小的數,為 2.

【難度】

解答

這道題可以採用遞迴來解決,注意,這道題陣列是有序的,所以它有如下特點:

(1)、當 兩個陣列的長度為偶數時:

我來舉個例子說明他擁有的特點吧。我們假定
arr1 = [1, 2,3,4],arr2 = [3,4,5,6]。則陣列的長度為 n = 4。

【遞迴打卡1】在兩個長度相等的排序陣列中找到上中位數

分別選出這兩個陣列的上中位數的下標,即

mid1 = (n-1)/2 = 1。

mid2 = (n - 1)/2 = 1。

【遞迴打卡1】在兩個長度相等的排序陣列中找到上中位數

假如 arr2[mid2] > arr2[mid1],那麼我們要找的目標數是一定存在於 arr1[mid1+1...n] 和 arr2[0...mid2]中。而不可能存在於 arr1[0...mid1] 和 arr2[mid2+1...n] 之中。

【遞迴打卡1】在兩個長度相等的排序陣列中找到上中位數

也就是說,我們接下來只需要在arr1[mid1+1...n] 和 arr2[0...mid2] 中查詢就行了。

(2)、當兩個陣列的長度為奇數時:

假定 arr1 = [1, 2,3,4,5],arr2 = [3,4,5,6,7]。則陣列的長度為 n = 5。

mid1 = (n-1)/2 = 2。

mid2 = (n - 1)/2 = 2。

這個時候如果 arr2[mid2] > arr1[mid1] 時,則和上面那個情況有點小差別,這時候目標數只存在於 arr1[mid1...n] 和 arr2[0...mid2]中。注意他們的差別,從arr1[mid1+1...n] => arr1[mid1...n]。

理解了這個原理,配合上程式碼會更好理解,程式碼如下:

    public static int getUpMedian(int[] arr1, int[] arr2) {
        if(arr1 == null || arr2 == null )
            return -1;
        // 開始尋找
        return find(arr1, 0, arr1.length - 1, arr2, 0, arr2.length - 1);
    }

    public static int find(int[] arr1, int l1, int r1, int[] arr2, int l2, int r2) {
        int mid1 = l1 + (r1 - l1) / 2;
        int mid2 = l2 + (r2 - l2) / 2;
        // 表示陣列只剩下一個數,把兩個陣列中較小的數返回去
        if (l1 >= r1) {
            return Math.min(arr1[l1], arr2[l2]);
        }
        // 元素個數為奇數,則offset為0,為偶數則 offset 為 1
        int offset = ((r1 - l1 + 1) & 1) ^ 1;// 用位運算比較快
        if (arr1[mid1] < arr2[mid2]) {
            return find(arr1, mid1+offset, r1, arr2, l2, mid2);
        } else if (arr1[mid1] > arr2[mid2]) {
            return find(arr1, l1, mid1, arr2, mid2 + offset, r2);
        } else {
            return arr1[mid1];// 返回 arr2[mid2]也可以。
        }
    }

也可以用迭代來做,反而更加簡單,迭代版本如下:

    // 迭代版本
    public int getUpMedian2(int[] arr1, int[] arr2) {
        if (arr1 == null || arr2 == null) {
            return -1;
        }
        int l1 = 0;
        int r1 = arr1.length - 1;
        int l2 = 0;
        int r2 = arr2.length - 1;
        int mid1 = 0;
        int mid2 = 0;
        int offset = 0;
        while (l1 < r1) {
            mid1 = l1 + (r1 - l1) / 2;
            mid2 = l2 + (r2 - l2) / 2;
            offset = ((r1 - l1 + 1) & 1)^1;
            if (arr1[mid1] < arr2[mid2]) {
                l1 = mid1 + offset;
                r2 = mid2;
            } else if (arr1[mid1] > arr2[mid2]) {
                r1 = mid1;
                l2 = mid2 + offset;
            } else {
                return arr2[mid1];
            }
        }
        return Math.min(arr1[l1], arr2[l2]);
    }

【遞迴打卡1】在兩個長度相等的排序陣列中找到上中位數

相關文章