飯后茶思:求兩遞增數(shù)組的中位數(shù)(O(log(m + n)))你會嗎?

原題可以在 LeetCode 上找到,地址:Median of Two Sorted Arrays,難度級別為困難。

不要被困難級別唬到,看完這篇文章,相信你也可以做出來。

乍一看求兩遞增數(shù)組的中位數(shù)并不是很難,因為兩序列有序,所以我們很容想到時間復(fù)雜度為 O(m + n) 的做法:依次取出兩數(shù)組中較小的元素,然后找到中間的元素即可。

但這樣并不是最優(yōu)的,我們還可以實現(xiàn)時間復(fù)雜度為 O(log(m + n)) 的算法,自然而然地我們就能想到二分查找法來求解。

題目是讓找兩數(shù)組的中位數(shù),我們可以泛化為求兩數(shù)組中第 k 大的元素,那么,求中位數(shù)就是其中的一個特例而已。helper 函數(shù)所起到的作用就是求兩數(shù)組中第 k 大的元素,下面來解釋其原理:

假設(shè)數(shù)組分別記為 A,B,當(dāng)前需要搜索第 k 大的數(shù),于是我們可以考慮從數(shù)組 A 中取出前 m 個元素,從數(shù)組 B 中取出前 k - m 個元素。由于數(shù)組 A,B 分別排序,則 A[m - 1] 大于從數(shù)組 A 中取出的其他所有元素,B[k - m - 1] 大于數(shù)組 B 中取出的其他所有元素。此時,盡管取出元素之間的相對大小關(guān)系不確定,但 A[m - 1]B[k - m - 1] 的較大者一定是這 k 個元素中最大的。那么,較小的那個元素一定不是第 k 大的,這里留給讀者自己想象。

為敘述方便,假設(shè) A[m - 1] 是較小的那個元素,那么我們可以把 A[0],A[1]...A[m - 1] 排除掉,并且更新 k 值為 k - m,也就是下一次就是從剩余的元素中尋找第 k - m 大的元素,這樣,我們就完成了一次范圍縮小,同理進(jìn)行下一輪的操作。

那么什么時候停止操作呢?分兩種情況:

  1. 當(dāng)某個數(shù)組的數(shù)都被取完了,那么直接返回另一個數(shù)組的后 k 個元素即可。

  2. 當(dāng) k = 1 時,也就是只需再找一個數(shù)即可,也就是取兩者當(dāng)前較小的那個即可。

特別地,我們選取 m = k / 2,下面是我畫的草圖,希望能幫助大家理解。

借助上面的理論,你能寫出相關(guān)代碼了嗎?

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len = nums1.length + nums2.length;
        if (len % 2 == 0) {
            return (helper(nums1, 0, nums2, 0, len / 2) + helper(nums1, 0, nums2, 0, len / 2 + 1)) / 2.0;
        }
        return helper(nums1, 0, nums2, 0, (len + 1) / 2);
    }

    private int helper(int[] nums1, int m, int[] nums2, int n, int k) {
        if (m >= nums1.length) return nums2[n + k - 1];
        if (n >= nums2.length) return nums1[m + k - 1];
        if (k == 1) return Math.min(nums1[m], nums2[n]);

        int p1 = m + k / 2 - 1;
        int p2 = n + k / 2 - 1;
        int mid1 = p1 < nums1.length ? nums1[p1] : Integer.MAX_VALUE;
        int mid2 = p2 < nums2.length ? nums2[p2] : Integer.MAX_VALUE;
        if (mid1 < mid2) {
            return helper(nums1, m + k / 2, nums2, n, k - k / 2);
        }
        return helper(nums1, m, nums2, n + k / 2, k - k / 2);
    }
}

我的 GitHub 上本題的題解地址:Median of Two Sorted Arrays,希望可以幫到你。

如果你同我一樣熱愛數(shù)據(jù)結(jié)構(gòu)、算法、LeetCode,可以關(guān)注我 GitHub 上的 LeetCode 題解:awesome-java-leetcode

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容