LeetCode_4_兩個排序數組的中位數

LeetCode_4_兩個排序數組的中位數

題目描述

兩個排序數組的中位數 Median of Two Sorted Arrays算法

給定兩個大小爲 m 和 n 的有序數組 nums1nums2
請找出這兩個有序數組的中位數。要求算法的時間複雜度爲 $O(\log (m+n))$ 。數組

示例 1:函數

nums1 = [1, 3]
nums2 = [2]
中位數是 2.0

示例 2:code

nums1 = [1, 2]
nums2 = [3, 4]
中位數是 (2 + 3)/2 = 2.5

Tags: 數組,二分查找,分治算法排序

解決思路

題目給定兩個有序的數組,找出中位數並不困難,最簡單的一個循環就行,時間複雜度 $O(m+n)$ 。可是題目要求時間複雜度爲 $O(\log (m+n))$ 就是一個大問題,具體思路採用二分查找,以下:遞歸

其中k 表示要求的中位數的位置,初始化 $k = (m + n + 1) / 2$ 和 $k = (m + n + 2) / 2$,即 $m + n$ 是偶數時爲中間兩個, $m + n$ 是奇數時爲中位數的後面一個。ip

首先將 A 劃分爲左右兩部分,其中 $i = k / 2$ ,$length(left_A) = i,length(right_A) = k - i$leetcode

left_A             |        right_A
A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]

而後將 B 劃分爲左右兩部分,其中 $j = k / 2$ ,$length(left_A) = j,length(right_A) = k - j$get

left_B             |        right_B
B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

則,A、B 數組可分爲左右兩部分,以下:io

left          |          right
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]

劃重點來了

若是,$A[i-1] > B[j-1]$,則說明,中位數必定在 $left_A、right_A、right_B$中,這樣就排除了$left_B$,想一想這是爲何?
由於有$A[i-1] > B[j-1]$ 不妨設 $A[0] > B[p],p=0,1,2,\ldots,j-1$ 則中位數必定不在$left_B$中,因此縮小查找範圍。

left          |          right
A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]
                         |  B[j], B[j+1], ..., B[n-1]

若是,$A[i-1] < B[j-1]$,則說明,中位數必定在 $right_A、left_B、right_B$中,這樣就排除了$left_A$,想一想這是爲何?理由同上。

left          |          right
                         |  A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

接下來,將縮小範圍的新數組 A 或者 B 按一樣的劃分,一樣的縮小範圍,就可獲得最後結果。

由上可得,方法爲二分查找,定義遞歸函數,肯定遞歸函數的出口爲:

  • 當某個數組的數都被取完了,那麼直接返回另外一個數組剩下的的第 k 個元素便可。
  • 當 k = 1 時,也就是隻需再找一個數便可,也就是取二者當前較小的那個便可。

如何肯定奇數個數取中位數,偶數個數取中間兩個數的平均數,我想,利用整數除法的規則,很容易就獲得 中位數爲 (m + n + 1) >> 1 這個數與 (m + n + 2) >> 1 取平均值便可,當個數爲奇數時,兩個數就是中間一個數。

Code

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        int l = (m + n + 1) >> 1;
        int r = (m + n + 2) >> 1;
        int* ln = m > 0 ? &nums1[0] : nullptr;
        int* rn = n > 0 ? &nums2[0] : nullptr;
        return ( getKth(ln, m, rn, n, l) + getKth(ln, m, rn, n, r) ) / 2.0;
    }
    int getKth(int* ln, int m, int* rn, int n, int k) {
        if (m > n) {
            return getKth(rn, n, ln, m, k);
        }
        if (m == 0) {
            return rn[k - 1];
        }
        if (k == 1) {
            return min(ln[0], rn[0]);
        }
        int i = min(m, k / 2), j = min(n, k / 2);
        if (ln[i - 1] > rn [j - 1]) {
            return getKth(ln, m, rn + j, n - j, k - j);
        } else {
            return getKth(ln + i, m - i, rn, n, k - i);
        }
    }
};
相關文章
相關標籤/搜索