问题:设X[0:n-1]和Y[0:n-1]为两个数组,每个数组中含有n个已排好序的数。试设计一个O(logn)时间算法,找出X和Y的2n个数的中位数并输出。
问题分析:本来可以很简单的排序(O(n))输出中间两个数的,但是题目要求复杂度要O(logn),就有点麻烦了。主要就是对两个数组不断进行删除裁剪(这里说的删除裁剪并不是真的对数组元素进行删除,只是进行范围的缩小),直到X数组和Y数组只剩下两个元素,然后对这四个元素进行比较选出中位数。
具体方法:new两个数组X[]和Y[],然后用两个for循环进行初始化,接着用while循环进行缩小范围的操作,直到X和Y数组都只剩下两个元素。
while循环的内部操作:1判断X数组和Y数组是否只有两个元素,如果是的话,比较X[xleft]和Y[yleft]的大小,取大者为第一个中位数;然后比较X[xright]和Y[yright]的大小,取小的作为第二个中位数。2否则就比较X[xmid]和Y[ymid]的大小。1)如果X[xmid]<Y[ymid],则删除xmid左边的全部元素,同时删除Y数组的右边同个数的元素。注意一下对yright的赋值问题,因为如果Y数组元素个数这时是偶数的话,yright=ymid+1;否则就yright=ymid。2)如果X[xmid]>Y[ymid],则删除xmid右边的全部元素,同时删除Y数组的左边同个数的元素。也一样要注意一下对yleft的赋值问题。
以下是Java代码
import java.util.Scanner;
public class ZhongWeiShu {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("请帅哥输入数组的元素个数:");
Scanner input=new Scanner(System.in);
int n=input.nextInt();
//根据输入的数字n来创建两个数组X[]和Y[]
int[] x=new int[n];
int[] y=new int[n];
System.out.println("请输入第一个数组元素:");
for(int i=0;i<n;i++){
x[i]=input.nextInt();
}
System.out.println("请输入第二个数组元素:");
for(int i=0;i<n;i++){
y[i]=input.nextInt();
}
input.close();
//调用函数findZhongWeiShu()来输出中位数
findZhongWeiShu(x,y,n);
}
public static int findZhongWeiShu(int x[],int y[],int n){
int xleft=0,xright=n-1,yleft=0,yright=n-1;
//使用while(true)来无限循环直到break中断
while(true){
/*当X数组和Y数组都只剩下两个元素的时候
* 这时剩下四个数字,取xleft和yleft的较大者作为第一个中位数
* 取xright与yright地较小者作为第二个中位数
*/
if((xright-xleft)==1&&(yright-yleft)==1){
System.out.println("帅哥你的中位数是:");
System.out.println(((x[xleft]>=y[yleft])?x[xleft]:y[yleft])+" "+
((x[xright]<=y[yright])?x[xright]:y[yright]));
break;
}
else{
int xmid=(xleft+xright)/2;
int ymid=(yleft+yright)/2;
//比较X[xmid]跟Y[ymid]的大小
//如果相等说明这两个数都是中位数
if(x[xmid]==y[ymid]){
System.out.println("帅哥你的中位数是:");
System.out.println(x[xmid]+" "+x[xmid]);
break;
}
/*如果小于,则“删除”X数组左边全部元素,同时也要删除Y数组
* 从右边数过来和X数组删除的相同个数的元素
*/
else if(x[xmid]<y[ymid]){
//计算Y数组剩下的元素个数是否是偶数
if((yleft+yright+1)%2==0){
xleft=xmid;
yright=ymid+1;
}
else{
xleft=xmid;
yright=ymid;
}
}
else{
/*如果大于,则“删除”X数组右边全部元素,同时也要删除Y数组
* 从左边数过来和X数组删除的相同个数的元素
*/
if((xright+xleft+1)%2==0){
xright=xmid+1;
yleft=ymid;
}
else{
xright=xmid;
yleft=ymid;
}
}
}
}
return 0;
}
}