4. Median of Two Sorted Arrays

题目

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;
	}
}

运行结果




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值