查找兩個有序數組的中位數,時間復雜度為 O(log(m + n))


題目:
給定兩個大小為 m 和 n 的有序數組 nums1 和 nums2。

請你找出這兩個有序數組的中位數,並且要求算法的時間復雜度為 O(log(m + n))。

你可以假設 nums1 和 nums2 不會同時為空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

則中位數是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

則中位數是 (2 + 3)/2 = 2.5

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

首先明確幾個點:
1、兩個數組都是有序的

[1,3,5]
[2,4,6]
合並后中位數為3、4,分別分布在數組1和數組2中,那么以3、4為分隔點,在數量上:數組1的左邊元素個數 + 數組2的左邊 = 數組1的右邊 + 數組2右邊元素個數
再如:
[1,3,5]
[0,2,4,6]
合並后中位數為3,只在數組1中,那我們將3放入數組2中,[0,2,3,4,6]
剛才的推論依然成立
中位數左邊元素的數量等於中位數右邊元素的數量

2、 數組1中,中位數左邊最大的元素一定小於中位數右邊最小的元素,當數組2中也有中位數(如沒有則將中位數放入數組2中),數組2中位數右邊最小的元素一定大於數組1中位數左邊的元素,數組2中位數左邊的元素一定小於數組1中位數右邊的元素
即:
例1:6>1, 2<5
例2:4>1,2<5

2、一個數組有n個元素,則有n+1個插槽
3、一見log(m+n)便知與二分查找有關
代碼
class Solution {

/**
 * @param Integer[] $nums1
 * @param Integer[] $nums2
 * @return Float
 */
function findMedianSortedArrays($nums1, $nums2) {
    $n1 = count($nums1);
    $n2 = count($nums2);
    if($n1>$n2){
        return $this -> findMedianSortedArrays($nums2, $nums1); // 數組1的長度永遠不會比數組2更長
    }
    $k = intval(($n1+$n2+1)/2); // 總槽點數量二分之一
    $left = 0;    
    $right = $n1;
    while($left < $right){
        $m1 = intval($left + ($right-$left)/2); // 此處實現二分查找

        // 第一次查找時:當數組1是奇數個,我們認為m1是中位數,當數組1是偶數個,認為m1是中位數中較大的那個。

        $m2 = $k - $m1;                         // 兩個數組中位數的左邊元素數量相加等於總槽點數量的二分之一 

        if($nums1[$m1] < $nums2[$m2-1]){        // m1為數組1的的中位數或者較大的中位數 小於 數組2中位數左邊的最大值m2-1

            $left = $m1 + 1;                    // 此時說明數組1可以繼續向右查找,進入下一次二分查找

        }else{

            $right = $m1;                       //  否則已經找到中位數的位置,退出循環
        }
    }
    // 上面while循環的核心思想是:
    //    因為規范了 數組1的長度永遠不會比數組2更長, 所以當數組1長度為0時,數組2的中位數就是要求的中位數
    //    當數組1的長度為3時,數組2長度遠大於3,那么數組1對於所求的中位數影響有限。即最后得到的中位數如果在數組2中,則一定在第一次求得的中位數附近不超過3。如果中位數在數組1中,查詢次數更不會超過3,所以滿足 $left < $right 循環即可遍歷所有可能。

    $m1 = $left;
    $m2 = $k - $m1;
    // 處理邊界問題
    $c1 = max($m1<=0 ? PHP_INT_MIN : $nums1[$m1-1], $m2<=0 ? PHP_INT_MIN : $nums2[$m2-1]);
    if(($n1+$n2)%2 == 1){
        return $c1;
    }
    $c2 = min($m1 >= $n1 ? PHP_INT_MAX : $nums1[$m1], $m2 >= $n2 ? PHP_INT_MAX : $nums2[$m2]);
    return ($c1+$c2) * 0.5;
}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM