原始题目
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.
意思是给定了两个已经排序的数组大小分别为m和n,在O(log(m+n))的时间复杂度下,找到他们的中位数。
你可以假设两个数组不同时为空。
当看到这个题目的时候,我相信很多人的想法和我一样,是合并两个数组,排序,找到其中位数。几乎没有任何犹豫,不过后来一提交,超时!
这种最最简单的方法的时间复杂度为O(nlogn);显然大于了题目的要求。于是我想到了二分法,大家都知道二分法的时间复杂度是O(logn)。
首先我们要明白中位数的真正意义是将一个数组分为左右相等的两个部分,假设一个数组有n个数字,那么中+位数就是其第(n+1)/2小数字。即:【1,2,3,4,5,6,7】 n=7, median=(7+1)/ 2=4;
left_A | right_A
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
那么在两个数组中,
left_part | right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
※真正的中位数会在两个数组分别的中位数附近!所以我们先分别求出两个数组的中位数i和j(其实j是根据i出来的),然后比较A [ i - 1 ] < = B [ j ] and B [ j - 1 ] < = A [ i ],通过控制 i 来寻找,left_part多了 i- -,left_part少了,就i++,
※那么,我们要做的事情就是!!!找到一个满足条件的 i !!!!满足 A [ i - 1 ] < = B [ j ] and B [ j - 1 ] < = A [ i ] ,那么说明这两个数组已经被均分了即left_part元素个数=right_part元素个数,即中位数就是*MAX ( A[ i - 1 ] , B [ j - 1 ] )
直接上代码!
public static double soluiton(int[] A , int[] B) {
int m=A.length;
int n=B.length;
if(m>n) {//ensure m<=n because i=0~m,j=(m+n+1)/2 - i;
int[] tem=B;B=A;A=tem;
int temp=m;m=n;n=temp;
}
int begin=0,end=m;//the range of i
while(begin<=end) {//begin~end 为 i 的搜索范围
int i=(begin+end)/2;//the median of A
int j=(m+n+1)/2-i;//the median of B
if(i<end && B[j-1]>A[i]) {// B.Max[left_part]>A.Min[right_part] means i is too small
begin=i+1;
}else if(i>begin && A[i-1]>B[j]) {// A.Max[left_part]>B.Min[right_part] means i is too big
end=i-1;
}else{ // i is perfect
int Max_left=0;
if(i==0) {//if len(A)=0 or 1
Max_left = B[j-1];
}else if(j==0) {// len(B)=0 or 1
Max_left=A[i-1];
}else {
Max_left=Math.max(A[i-1], B[j-1]);
}if((m+n)%2==1) {//判断是奇数,直接出答案
return Max_left;
}
int Min_right=0;
if(i==m) {
Min_right=B[j];
}else if(j==n) {
Min_right=A[i];
}else {
Min_right=Math.min(A[i], B[j]);
}
return (Max_left+Min_right)/2.0;
}
}
return 0.0;
}
我们要考虑到其中一个数组为空或length=1的情况,以及一个数组为空,一个数组length=1的情况。
即 i = 0 , j = 0 , i = m , j = n .不过我还没怎么理解清楚 i = 0和 i = m的区别,后续再更新!!如果有大佬赐教,感激不尽,网上的看了,看不懂。。。
- 代码中的begin=i+1和end=i-1 是什么意思?
if(i<end && B[j-1]>A[i]) {// B.Max[left_part]>A.Min[right_part] means i is too small
begin=i+1;
}
解答:当B [ j - 1 ] > A [ i ] 時,说明A[i]的右边的某些值也在left_part,因为B的中位数>A的中位数,意味着它至少有可能大于A的中位数右边的1个或多个数。此时,我们就需要在【i+1~m】的范围里寻找新的 i ,来满足A [ i - 1 ] < = B [ j ] and B [ j - 1 ] < = A [ i ]。所以begin=i+1.
else if(i>begin && A[i-1]>B[j]) {// A.Max[left_part]>B.Min[right_part] means i is too big
end=i-1;
}
同理: 当 A [ i - 1 ] > B [ j ] 时,说明B [ j ] 右边的值跑到了left_part中了,所以我们需要在A中找一个更小的 i 来满足条件。此时我们需要在【0 ~ i-1】范围中搜索,所以end= i - 1。
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