求两个等长有序数组中位数算法问题

问题:设X[0:n-1]和Y[0:n-1]为两个数组,每个数组中含有n个已排好序的数。试设计一个O(logn)时间算法,找出X和Y的2n个数的中位数

思路:找出将大问题分割成较小规模的相同问题的切割点,并递归定义大问题与子问题之间的关系。

简单来说,就是比较两个区间的中位数,如果第一个区间的中位数比第二个大,那么就把第一个区间的范围缩小至它的前半段,把第二个区间缩小至它的后半段,然后重复上述过程

具体些,对于两个数组x,y,我们可以从他们中分别选取出一个中位数,并将两个数组的左右边界称之为xLeft,xRight,yLeft,yRight。对比两个中位数,如果X数组中的中位数大于Y数组中的中位数,且X数组中的元素个数为偶数个,则X数组被切割为X[xLeft,x+1],Y被切割为Y[y,yRight],如果X数组的元素个数不为偶数个的话,则直接将X切割为X[xLeft,x]。如果X数组的中位数小于Y数组的中位数,取值情况刚好相反。

递归关系:根据上面所述,对于原问题X[xLeft , xRight], Y[yLeft, yRight]。假设切割后的子问题为X[xLeft, x+1],Y[y,yRight]。则求解X[xLeft , xRight], Y[yLeft, yRight]问题的中位数,归结于求解子问题X[aLeft, x+1],Y[y,yRight]的中位数。

递归结束条件:当切割后得到的子问题的两个数组的长度都为2位时,整个递归结束。

Input:

第一行: n,为x和y数组的元素个数
第二行: x数组的n个数,用空格分隔
第三行: y数组的n个数,用空格分隔

Output:

中位数两个,用空格分隔

代码(C++):

<span style="font-family:Tahoma;">#include <iostream>
using namespace std;

int main(int argc, char** argv) {
	//  获取数组长度 
	int n; 
	cin>>n;
	//  分配两个数组(两个数组的左右端点的坐标和中间坐标)    
	int xleft = 0, yleft = 0, len = n, xright = n - 1, yright = n - 1, xmid, ymid;
	int x[n], y[n];
	//  获取两个数组的元素 
	for(int i = 0; i < n; i++){
		int j;
		cin>>j;
		x[i] = j;	
	}
	for(int i = 0; i < n; i++){
		int j;
		cin>>j;
		y[i] = j;	
	}
	//  如果数组长度为1,则其元素都为中位数 
	if(n == 1)
		cout<<x[0]<<"  "<<y[0];
	else{
		//  迭代循环
		while(true){
			//  如果两个数组都只剩下两个元素,则中位数一定在其中 
			if( (xright - xleft) == 1 && (yright - yleft) == 1){
				//  输出两个值 
				cout<<((x[xleft]>=y[yleft])?x[xleft]:y[yleft])<<" "<<((x[xright]<=y[yright])?x[xright]:y[yright]);
				break;
			}
			else{
				//  求解各个数组的中值
				xmid = (int)((xleft + xright)/2);  
    			ymid = (int)((yleft + yright)/2); 
    			//  如果x中值小于y中值
				if(x[xmid] < y[ymid]){
					//  如果y中现存的数列是偶数个,右边值加一  
 					if((yleft + yright + 1) % 2 == 0) {  
		             	xleft = xmid;  
		                yright = ymid + 1;  
		            }  
		            else {  
		                xleft = xmid;  
		                yright = ymid;  
		            } 
				}
				//  如果B中值小于x中值 
				else{
					//  如果x中现存的数列是偶数个,右边值加一  
					if((xleft + xright + 1) % 2 == 0) {  
	                	xright = xmid + 1;  
	                	yleft = ymid;  
	            	}  
	            	else {  
	                	xright = xmid;  
	                	yleft = ymid;  
	            	}    
				}
			}
		}
	}		
	return 0;
}</span>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值