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