题目
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)).
解题思路
这道题应该有更简洁的方法,我的解法过于复杂,需要考虑的情况和细节过多,而且比较难证明程序的正确性。
思路是这样的:首先找出两个数组中的中位数,如果这两个中位数相等,那么这个值就是两个数组合并后的中位数。如果不等,指向两个数组的指针就要分别移动,循环的结束条件:要么移动过程中出现以前被访问过的数,要么指针越界。
需要注意两点:
1. 指针的增量是小数组长度的(1/2)^i倍,当增量为0时,并非循环结束的条件,这时增量变为1;
2.p1=(small.length-1)/2;p2=large.length/2; //very important. 保证了程序的正确性。
代码
public class Solution{
public double findMedianSortedArrays(int[] nums1,int[] nums2){
int[] small=(nums1.length<=nums2.length)?nums1:nums2;
int[] large=(nums1.length>nums2.length)?nums1:nums2;
if(small.length==0) //if one of the arrays is empty
{
int len=large.length;
if(len%2==1)return large[len/2];
else return (large[len/2-1]+large[len/2])/2.0;
}
int N,tmp,diff=0,c=0;
int p1=(small.length-1)/2;
int p2=large.length/2;
boolean[] tag1=new boolean[small.length];
boolean[] tag2=new boolean[large.length];
for(int inc=small.length/4;;inc/=2){
//1:equal
if(small[p1]==large[p2]){N=1;diff=2*(p1+p2+1)-small.length-large.length;break;}
tag1[p1]=true; //update
tag2[p2]=true;
if(small[p1]<large[p2])
{
if(inc!=0) {p1+=inc;p2-=inc;}
else {p1++;p2--;}
//2:out of boundary {p1-1,0~P2+1} -> {p1,0~p2}
if(p1==small.length){
N=2;p1--;p2++;diff=p1+p2+1-large.length;c=0;
if(diff>0){
p2-=diff;
if(small[p1]>=large[p2+1]){p2++;p1=-1;}
}
else if(diff<0){
c-=diff;
if(small[p1]<=large[c-1]){c--;p1=-1;}
}
break;
}
//3:loop {p1-1,p1,p2,p2+1}->{p1,p1+1,p2,p2+1}
if(tag1[p1]==true && tag2[p2]==true){N=3;p1--;diff=2*(p1+p2+2)-small.length-large.length;break;}
}
else
{
if(inc!=0){p1-=inc;p2+=inc;}
else{p1--;p2++;}
//2:out of boundary {p1+1,p2-1~large.length} -> {p1,p2~large.length}
if(p1<0){
N=2;p1++;p2--;diff=p1+p2+1-small.length;c=large.length-1;
if(diff>0){
c-=diff;
if(small[p1]>=large[c+1]){c++;p1=-1;}
}
else if(diff<0){
p2-=diff;
if(small[p1]<=large[p2-1]){p2--;p1=-1;}
}
break;
}
//3:loop {p1,p1+1,p2-1,p2} -> {p1,p1+1,p2,p2+1}
if(tag1[p1]==true && tag2[p2]==true){N=3;p2--;diff=2*(p1+p2+2)-small.length-large.length;break;}
}
}
int c1,c2;
if((small.length+large.length)%2==1) //select one number
{
switch(N)
{
case 1:return small[p1];
case 2:p2=(c+p2)/2;
if(p1==-1)
return large[p2];
else
{
if(small[p1]<=large[p2])
return large[p2];
else if(small[p1]<=large[p2+1])
return small[p1];
else
return large[p2+1];
}
case 3:if(diff==1) //the second number
{
c1=small[p1]<=large[p2]?small[p1]:large[p2];
c2=small[p1+1]<=large[p2+1]?small[p1+1]:large[p2+1];
c2=(small[p1]+large[p2]-c1)<=c2?(small[p1]+large[p2]-c1):c2;
}
else //the third number
{
c1=small[p1+1]>=large[p2+1]?small[p1+1]:large[p2+1];
c2=small[p1]>=large[p2]?small[p1]:large[p2];
c2=(small[p1+1]+large[p2+1]-c1)>=c2?(small[p1+1]+large[p2+1]-c1):c2;
}
return c2;
}
}
else //select two numbers
{
switch(N){
case 1:return small[p1];
case 2:p2=(c+p2)/2;
if(p1==-1)
return (large[p2]+large[p2+1])/2.0;
else{
if(c==p2)
return (large[p2]+small[p1])/2.0;
else if(small[p1]<=large[p2-1])
return (large[p2-1]+large[p2])/2.0;
else if(small[p1]>=large[p2+1])
return (large[p2]+large[p2+1])/2.0;
else
return (large[p2]+small[p1])/2.0;
}
case 3:c1=small[p1]<=large[p2]?small[p1]:large[p2];
c2=small[p1+1]>=large[p2+1]?small[p1+1]:large[p2+1];
return (small[p1]+small[p1+1]+large[p2]+large[p2+1]-c1-c2)/2.0;
}
}
return 0;
}
}
运行结果