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.0Example 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