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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章