题目如下:
两个排序的数组A和B分别含有m和n个数,找到两个排序数组的中位数,要求时间复杂度应为O(log (m+n))。
样例
给出数组A = [1,2,3,4,5,6] B = [2,3,4,5],中位数3.5
给出数组A = [1,2,3] B = [4,5],中位数 3
解题思路:
【注意,下述所说的中位数是思维上面的中位数位置,并不是真正的数组中位数。两个数组都是独立的并且不可重复元素已排序,在两个数组间寻找中位数一般需要知道总个数,但由于两个数组间可能存在相同元素,因此遍历出总个数后复杂度已经上升到O(m+n)的高度了,不符题意。从题意给出的O(log(m+n))可以推断出,此复杂度解法可以使用分治法,但在不知道总个数的情况下使用分治法对某个数组进行操作也是困难的,因此采用了动态规划。由于两个数组间存在并集关系,所以两个数组间的中位数可看做整体数组中位数的范围,如果数组a的中位数p1小于数组b的中位数p2,那么他们并集的中位数肯定在于[p1-a(n-1)]-[b(0)-p2]之间,可舍去a[0]-p1区间,可能有人会疑问,那么p2-b(n-1)能否舍去,当然是不能的,因为我们操作的是整个总数组,而不是并集数组,并不能判断中位数不在此区间。反之相反规律,如此反复取舍,每次将会舍去不必要的区间,并且p1与p2会无限接近并集数组中位数。】
思路实现代码如下:
void Method(int *s,int slen,int *e,int elen)
{
int m=slen+elen,t,i=0,p=m&1?1:2;
int u=0,q=0;
int q1,q2,l1,l2;
int *a,*b;
slen>elen?Method(e,elen,s,slen),p=0:0;
for(i=0; i<p; ++i)
{
t=m/2+1,l1=slen,l2=elen,
a=s,b=e;
i==1?q=u,--t:0;
while(t)
{
l1==0?u=b[t-1],t=0:0;
t==1?u=min(a[0],b[0]),t=0:0;
t!=0?q1 = min(t / 2, l1),
q2 = t - q1,a[q1-1]>b[q2-1]?
b+=q2,l2-=q2,t-=q2:
a[q1-1]<b[q2-1]?
(a+=q1,l1-=q1,t-=q1):
(u=a[q1-1],t=0):0;
}
}
printf("%f\n",m&1?(double)u:(double)(u+q)/2);
}