php算法題:尋找有序數組的中位數

4. Find Median Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively.算法

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).數組

You may assume nums1 and nums2 cannot be both empty.this

Example 1:code

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

The median is 2.0

Example 2:it

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

The median is (2 + 3)/2 = 2.5

1、按時間複雜度O(m+n)解

先來解釋一下什麼是中位數

以下:
[3,4,5] , 那麼這組數的中位數就是4
[3,4,5,6] , 那麼這組數的中位數就是 (4+5)/2 = 4.5

開始沒有注意到時間複雜度,但按照O(m+n)解,也花了我很多時間,多是好久沒有接觸算法的緣故。io

2、二分法求解

根據上面對中位數的解釋,以及對於題目中給出的有序數組nums1[m],nums2[n]。能夠想到,最後確定是nums1的一部分在中位數的左邊,一部分數在中位數的右邊,nums2同理。function

因此我們能夠將nums1和nums2,合併後劃分紅,左右兩個數組。class

nums1[0],...,nums1[i-1] | nums1[i] ... nums1[m-1]
nums2[0],...,nums2[j-1] | nums2[j] ... nums2[m-1]

也能夠當作是下面這種im

nums1[0],...,nums1[i-1],nums2[0],...,nums2[j-1] | nums1[i] ... nums1[m-1],nums2[j] ... nums2[m-1]

左右兩個數組的總數多是奇數,也多是偶數。因此規定,若是是奇數,那麼左邊比右邊多一個,若是是偶數,那麼左右兩邊相等。總結

這裏來講一下i和j的關係
左邊數組的個數 t =(int)(m+n+1)/2
j = t - i.

理解清楚了i和j的關係以後,那麼接下來就要判斷中位數了
抓住數組有序這個條件。
可知若是知足中位數的條件左邊最大的數leftMax 小於 右邊最小的數rightMin
而且左邊數組個數必定是等於右邊數組個數,或者是比右邊數組個數多1個。

最重要的來了
根據上面一系列的條件,那麼如今要作的就是經過二分法選出合適的i,進而獲得中位數

還得考慮邊界問題,這個在下面代碼中給出註釋

代碼以下:

class Solution{
    /**
     * @param Integer[] $nums1
     * @param Integer[] $nums2
     * @return Float
     */
    function findMedianSortedArrays($nums1, $nums2) {
        $m = count($nums1);
        $n = count($nums2);
        //若是$m>$n時,後面的$j會可能小於0。也就是上面提到的不等式( t =(int)(m+n+1)/2。j = t - i.)
        if($m>$n) return $this->findMedianSortedArrays($nums2,$nums1);
        
        $t = (int)(($m+$n+1)/2);
        $i = 0;
        $j = 0;
        
        /** 要理解清楚下面兩組max,min的意思 */
        $leftMax = 0;//左邊數組的最大值
        $rightMin = 0;//右邊數組的最小值
        $iMax = $m;//二分法的右邊界
        $iMin = 0;//二分法的左邊界
        
        while($iMax >= $iMin){
            //二分法
            $i = (int)(($iMax+$iMin)/2);
            $j = $t-$i;
            if ($i>0 && $j<$n && $nums1[$i-1] > $nums2[$j]){//利用數組有序,能夠只比較一次
                $iMax=$i-1;
            }elseif ($j>0 && $i<$m && $nums1[$i] < $nums2[$j-1]){//利用數組有序,能夠只比較一次
                $iMin=$i+1;
            }else{//二分到最後 最佳位置
                if ($i==0){
                    $leftMax = $nums2[$j-1];
                }elseif ($j==0){
                    $leftMax = $nums1[$i-1];
                }else {
                    $leftMax = max($nums2[$j-1],$nums1[$i-1]);
                }
                if(($m+$n)%2 == 1){//數組和是奇數
                    return $leftMax;
                }
                //數組和是奇數
                if ($i == $m){
                    $rightMin = $nums2[$j];
                }elseif ($j == $n){
                    $rightMin = $nums1[$i];
                }else {
                    $rightMin = min($nums2[$j],$nums1[$i]);
                }
                return ($leftMax+$rightMin)/2;
            }
        }        
    }
    }

總結

講解問題的能力還有待進一步提升。若是有問題歡迎私聊。

相關文章
相關標籤/搜索