PAT (Advanced Level) 1029. Median (25) 求两个有序数组的中位数,二分

 

Given an increasing sequence S of N integers, the median is the number at the middle position. For example, the median of S1={11, 12, 13, 14} is 12, and the median of S2={9, 10, 15, 16, 17} is 15. The median of two sequences is defined to be the median of the nondecreasing sequence which contains all the elements of both sequences. For example, the median of S1 and S2 is 13.

Given two increasing sequences of integers, you are asked to find their median.

Input

Each input file contains one test case. Each case occupies 2 lines, each gives the information of a sequence. For each sequence, the first positive integer N (<=1000000) is the size of that sequence. Then N integers follow, separated by a space. It is guaranteed that all the integers are in the range of long int.

Output

For each test case you should output the median of the two given sequences in a line.

Sample Input
4 11 12 13 14
5 9 10 15 16 17
Sample Output
13
直接归并的话,在k较大时,效率很低。
可以用二分法来做。
举个例子,有两个数组a和b升序排列,我们可以把它们看成两个帮派,帮派里的兄弟按照实力从弱到强进行升序排列,通常杂事都推给实力弱的人做。
由于有新的帮派c崛起了,对这两个帮派造成了威胁。这两个帮派a和b决定进行合并,这些家伙都有点小心机,都希望合并后,从隔壁帮派过来的,比自己强的少点,比自己弱的多点,这样自己的地位就高点,以后可以少干点活。
好了,现在要找两个帮派合并后第10弱的人,因为合并后最弱的10个人要组成一个打杂小队。如果用归并的话,就先让两个帮派最弱的打一架,输的一方再派出第二弱的,依次类推。这样打一架确定1个人,打过10架后,最弱的10个人确定,打杂小队成立了。
有个机智的哥们说这样太麻烦,既然每个帮派原本都给自己的兄弟排过序。我们可以让原本两个帮派第5弱的人a[4]和b[4]打一架,若a[4]<b[4],即b帮派的哥们赢了,说明合并a[4]最多能再升4级(干掉b[0]b[1]b[2]b[3],从第5弱升到第9弱,从而a[0]a[1]a[2]a[3]a[4]这5个可以直接加入打杂小队,打一架直接确定了一半的人,剩下的人可以用同样的方法确定。万一打平就更好了,直接确定10个最弱的。
 
 
 
 
/*2015.7.23cyq*/
#include <iostream>
using namespace std;

long A[1000001];
long B[1000001];

int findKth(long A[],long B[],int Na,int Nb,int k){
	if(Na>Nb)//保证数组A较小
		return findKth(B,A,Nb,Na,k);
	if(Na==0)
		return B[k-1];
	if(k==1)
		return min(A[0],B[0]);

	int ia=min(k/2,Na);//数组A可能还不够k/2个元素
	int ib=k-ia;
	if(A[ia-1]<B[ib-1])//舍弃数组A前面一段
		return findKth(A+ia,B,Na-ia,Nb,k-ia);
	else if(A[ia-1]>B[ib-1])//舍弃数组B前面一段
		return findKth(A,B+ib,Na,Nb-ib,k-ib);
	else//相等,两个随意输出一个
		return A[ia-1];

}

int main(){
	int NA,NB;
	scanf("%d",&NA);
	for(int i=0;i<NA;i++)
		scanf("%ld",&A[i]);
	scanf("%d",&NB);
	for(int i=0;i<NB;i++)
		scanf("%ld",&B[i]);
	int mid;
	long result;
	if((NA+NB)%2==0)
		mid=(NA+NB)/2;
	else
		mid=(NA+NB)/2+1;
	printf("%ld",findKth(A,B,NA,NB,mid));
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值