LeetCode(4)

Description :

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)).

Example 1:
nums1 = [1, 3] nums2 = [2]
The median is 2.0

Example 2:
nums1 = [1, 2] nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

思路:
直接思路: 合併兩個數列 ->排序->找中位數 .時間複雜度: O((m+n)log(m+n)). 但要求 : O(log(m+n)) ; 考察點 :二分查找 .

先看 : 如何找到兩個數列的”第 k 小的數” , 即程序中 getKth ( A , B , k )函數的實現 .例如 : A = [ 1,3,5,7 ] ; B = [ 2,4,6,8,9,10 ] ; 要求取第 7 個小的數 , len(A) = 4 , len(B) = 6 ; k/2 = 7/2 = 3 , 那我們來看 A和B 數組第 3 小的數: 有A[2]=5 ; B[2]=6 ; 而 A[2] < B[2] ; 則A[2] 以及比他小的數 A[1] A[2] 中 必然不可能有第7個小的數 .證明如下圖 :
比較
圖可以清晰看出: A[ 0 : 2 ] 這三個數絕不可能是第 7 個小的數.
A[2] 最多是個第五小 .至此 .我們把這個三個數”刪掉” ,問題就轉化爲了求 : getkth( A,B,k-3 ) 即 getkth( A,B,4 )

那取中位數的問題也是一樣 :

class Solution {  
public:  
    double find(int num1[],int len1, int num2[],int len2) {  
        //總長度的一半  
        int left = (len1 + len2 + 1) / 2;   // 5
        int right = (len1 + len2 + 2  ) / 2;    //6
        //對兩個數組分治, 如果最後得到 2 個值 ,那就取平均.
        return (getkth(num1, len1 ,num2, len2, left) + 
            getkth(num1, len1, num2, len2, right)) / 2.0;  
    }  

    int getkth(int n1[],int len1, int n2[],int len2, int k){  
       // 位置交換是是爲了確保 len1 < len2 方便操作
        if (len1 > len2)    
            return getkth(n2, len2, n1, len1, k); //重排 
        if (len1 == 0)   //遞歸出口1
            return n2[k - 1];  
        if (k == 1)     //遞歸出口2
            return min(n1[0], n2[0]);  

        //遞歸過程  
        int i = min(len1, k/2 ), j = min(len2, k/2 );  //i= 2,j= 2
        if (n1[i - 1] > n2[j - 1])  
            return getkth(n1,  len1,  n2+j, len2-j, k-j);  
        else  
            return getkth(n1+i, len1-i, n2, len2, k-i);  
        return 0;  
    }        
};
int main(){
    Solution aa;
    int a[] = {1,2,3,4,5,11,12} ; int m = 7;
    int b[] = {2,4,6,8,10} ;  int n= 5;
    cout<<aa.find(a,m,b,n);
    return 0;
}


講解 :

以測試用例爲例 :
a[] = {1,2,3,4,5} ; b[] = {2,4,6,8,10};
int left = (len1 + len2 + 1)/2; // =5
int right = (len1 + len2 + 2 )/2; // =6
如果有 10 個數, 那麼就是取 第五小和第六小的數的平均值 . left == 5 ; right == 6 ,
如果有 9 個數, 那麼就是取 第五小的數 . left == 5 ; right == 5 ,
所以將 left right 傳入 getkth(num1, len1 ,num2, len2, left) 然後在遞歸中 k/2 就變成了我們開頭提到的常規操作了 .



Python 解法 1:

class Solution:
    def findKth(self, A, B, k):
        if len(A) == 0:  return B[k - 1]
        if len(B) == 0:  return A[k - 1]
        if k == 1:  # 遞歸基:尋找兩個數中的第1小
            return min(A[0], B[0])

        a = A[ k/2 - 1] if len(A) >= k/2  else None
        b = B[ k/2 - 1] if len(B) >= k/2  else None

        if b is None or (a is not None and a < b):
            return self.findKth(A[k / 2:], B, k - k / 2)
        return self.findKth(A, B[k / 2:], k - k / 2)

    def findMedianSortedArrays(self, A, B):
        n = len(A) + len(B)
        if n % 2 == 1:
            # n是奇數, 如 5 , 5/2 = 2, 就是中位數
            return self.findKth(A, B, n / 2 + 1)
        else:
            smaller = self.findKth(A, B, n / 2)
            bigger = self.findKth(A, B, n / 2 + 1)
            return (smaller + bigger) / 2.0

    def findKth(self, A, B, k):
        if len(A) == 0:
            return B[k - 1]
        if len(B) == 0:
            return A[k - 1]
        if k == 1:
            return min(A[0], B[0])

        a = A[k / 2 - 1] if len(A) >= k / 2 else None
        b = B[k / 2 - 1] if len(B) >= k / 2 else None

        if b is None or (a is not None and a < b):
            return self.findKth(A[k / 2:], B, k - k / 2)
        return self.findKth(A, B[k / 2:], k - k / 2)

class Solution(object):
    def findMedianSortedArrays(self, a, b):
        c = a+b
        c.sort()
        m = len(c) / 2 
        mm = len(c) % 2
        if mm > 0 :
            return c[int(m)]
        return (c[int(m)-1]+c[int(m)])/2.# + (c[m-1]+c[m])%2
a = Solution()
nums1 = [6,7,8,9,10,99,117,2211,]
nums2 = [6]               
print(a.findMedianSortedArrays(nums1,nums2))


當然, pytohn 也有最簡單 最學不到東西的解法 :

class Solution(object):
    def findMedianSortedArrays(self, a, b):
        c = a+b
        c.sort()

        m = len(c) / 2 
        mm = len(c) % 2
        if mm > 0 :
            return c[int(m)]
        return (c[int(m)-1]+c[int(m)])/2.    # + (c[m-1]+c[m])%2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章