5分鐘帶你領略:分治算法用到極限是什麼樣子?

首先擺上題目:數組

剛開始,看到時間複雜度爲O(log(m+n)),立馬就會想到二分法,沒錯,可是針對這一題而言,拿到的是兩個數組,兩個數組長度的和爲奇數和偶數怎麼處理?遇到什麼狀況進行二分?怎麼分?這是咱們必須考慮的問題。函數

1、什麼是中位數?

首先,鞏固一下中位數的概念: 有n個已經排好序的數。ui

  • 對於n爲奇數的狀況,中位數則是第(n+1)/2個,即最中間的那個數。spa

  • 對於n爲偶數的狀況,中位數則是第n/2個數和第n/2 + 1個數的算術平均值。code

2、數組總長度奇數和偶數的狀況怎麼處理?

設總長度爲n,找到第(n+1)/2個數,再找到第(n+2)/2個數 (注意:索引值都向下取整)。 而後,求兩個數的平均值,便是最後要求的中位數。這樣能夠涵蓋奇數和偶數的任一狀況。cdn

3、遇到什麼狀況進行二分?怎麼分?

回到原題的起點,咱們是要找到特定位置的數,那麼想想能夠經過什麼方式排除絕對不屬於這個位置的數?blog

好比如今兩個數組是[1, 2, 4, 6, 8], [5, 7, 9,11]。總長度爲9,中位數爲第5個,一個數組還好辦,不過如今是兩個數組的狀況,咱們採起一個比較巧妙的方式得到第5個數:索引

  • step1: 將5/2, 向下取整即爲2,比較兩個數組的第二個數,對應爲2和7,明顯前者比後者小,那麼如今直接把第一個數組的前2個數剔除,由於它們百分之百在中位數的前面。it

  • step2: 那麼,如今咱們肯定了前2個數,那即將要求的就是後面全部的數字中排第3的數了。按照以前的作法,3/2,向下取整爲1, 比較兩個數組的第一個數,對應4和5, 前者比後者小,直接把第一個數組的前1個數剔除,由於百分之百在中位數的前面,不用考慮。io

  • step3: OK,如今咱們肯定了前三個數,即將要求的就是後面全部的數字中排第2的數了,依照上述作法,咱們剔除了5。

  • step4: 如今肯定了前四個數,即將要求的就是後面全部的數字中第1個數了,直接比較目前兩個數組的第一個數便可,6 < 7, 咱們取6。完成!

將問題通常化就是獲取第k個數,取兩個數組中第k/2個數進行比較,若是比較小,就把這個數組的前k/2個元素所有剔除,依次循環,直到k爲1或者有一個數組爲空。

4、 若是k/2比其中一個數組的長度還要大怎麼辦?

這種狀況,咱們只須要取這個數組末尾的元素便可。

5、JS代碼展現

代碼以下:

//找到第k大的元素
const findKMax = (num1, start1, end1, num2, start2, end2, k) => {
    let len1 = end1 - start1 + 1;
    let len2 = end2 - start2 + 1;
    //這裏我是來保證num1的長度必定小於num2,這樣肯定num1爲空,直接來取num2的第k個數
    if (len1 > len2)
        return findKMax(num2, start2, end2, num1, start1, end1, k);
    if (len1 == 0) return num2[start2 + k - 1];

    if (k == 1) return Math.min(num1[start1], num2[start2]);
    // |0這個操做爲向下取整
    //若是k/2比其中一個數組的長度還要大,取數組末尾元素便可
    let i = start1 + Math.min(len1, k / 2 | 0) - 1;
    let j = start2 + Math.min(len2, k / 2 | 0) - 1;

    if (num1[i] > num2[j])
        //已經剔除j - start2 + 1個元素
        return findKMax(num1, start1, end1, num2, j + 1, end2, k - (j - start2 + 1));
    else
        //已經剔除i - start1 + 1個元素
        return findKMax(num1, i + 1, end1, num2, start2, end2, k - (i - start1 + 1));
}
//核心函數
const findMedianSortedArrays = (nums1, nums2) => {
    let m = nums1.length;
    let n = nums2.length;
    //向下取整
    let left = (m + n + 1) / 2 | 0;
    let right = (m + n + 2) / 2 | 0;
    
    //處理了數組總長度爲奇數和偶數的狀況
    return (findKMax(nums1, 0, nums1.length - 1, nums2, 0, nums2.length - 1, left) +
        findKMax(nums1, 0, nums1.length - 1, nums2, 0, nums2.length - 1, right)) * 0.5;
}
複製代碼

成功AC!

相關文章
相關標籤/搜索