1、 设X[0:n-1]和Y[0:n-1]为两个数组,每个数组中含有n个已经排好序的数。试设计一个O(logn)时间的分治算法,找出X和Y的2n个数的中位数,并证明算法的时间复杂性为O(logn)
答:找出两个有序数组的中位数最简单暴力的方法是将两个数组合并成一个数组,然后找出中间那个数字。这种算法时间复杂度为O(n).
用分治算法解决,求出两个数组的中位数,然后比较这两个中位数的大小。
(1).如果这两个中位数相等,那么合并后的中位数一定是这个数。
(2)如果前面数组的中位数小于后面数组的,那么第一个数组中位数前的元素和第二个数组中位数后面的元素肯定不是合并后数组的中位数
(3)同理,如果第一个数组中位数大于第二个中位数,那么第一个数组中位数后的元素和第二个数组中位数前面的元素肯定不是合并后的中位数。
(4)将两个数组分别再分成两部分递归寻找中位数,最后找出中位数。
程序代码:
#include
#include
usingstd::vector;
using namespacestd;
/* run thisprogram using the console pauser or add your own getch,system("pause") or input loop */
float mid(intm, int n,int arry[])//该函数是为了找出中位数
{
int middle = (n+m+1)/2;
float re;
if((n-m)%2==0)
re = arry[middle]/1.0; //如果数组的个数为奇数,直接取中间值
else
re = (arry[middle-1] + arry[middle])/2.0;//偶数则取中间两个数的平均数
return re;
}
floatfindmid(int arry1[],int arry2[],int b1,int b2,int l1,int l2)
{
int mid1 = (b1 + l1 + 1)/2;//中间位置
int mid2 = (b2 + l2 + 1)/2;
float mm1,mm2;
mm1 = mid(b1,l1,arry1);//找出数组的中位数
mm2 = mid(b2,l2,arry2);
if(l1==b1 && l2==b2)
return (mm1 + mm2)/2.0;//如果两个数组都只剩一个元素,则取两个数组中位数的平均值
if(mm1 == mm2)
return mm1;//中位数相等直接返回该中位数
else if(mm1 < mm2) //第一个数组中位数小于第二个中位数,则舍掉第一个中位数前的数和第二个中位数后的数
{
if((l2-b2)%2!=0)
returnfindmid(arry1,arry2,mid1,b2,l1,mid2-1);
else
return findmid(arry1,arry2,mid1,b2,l1,mid2);
}
else //第一个数组中位数大于第二个中位数,则舍掉第一个中位数后的数和第二个中位数前的数
{
if((l1-b1)%2!=0)
return findmid(arry1,arry2,b1,mid2,mid1-1,l2);
else
return findmid(arry1,arry2,b1,mid2,mid1,l2);
}
}
int main(intargc, char** argv) {
int arry1[5]={1,5,6,8,9}, arry2[5]={1,2,6,7,10},i;
cout<<"第一个有序数组:";
for(i=0;i<5;i++)
cout< cout< for(i=0;i<5;i++) cout< cout< cout< } 运行结果: 时间复杂度分析: 由于每次都是将数组分成两部分寻找中位数,从n,n/2,n/4,n/8……一直到1,所以时间复杂度为O(log2n).