两个有序序列,返回中位数(或者第k个)

这个问题其实蕴含了两道题目,一个是合并两个有序序列一个是查找合并后序列中的中位数(第二个问题,不需要实际的合并操作

合并有序序列比较简单,以下是代码供简单参考:

void merge_order(list<int>&des,const list<int>&a,const list<int>&b)
{
	for(auto i=a.cbegin(),j=b.cbegin();i!=a.cend()||j!=b.cend();){
		if(i==a.cend())
                    des.push_back(*j++);
		else if(j==b.cend())
                    des.push_back(*i++);
		else
		    *i<*j?des.push_back(*i++):des.push_back(*j++);
	}
}


中位数,偶数个数是中间两个数的平均值,奇数个数是中间值。

这里有一个巧妙的处理方法:

可以观察到,L=(N-1)/2  R=N/2   当N%2==1时,L==R,  当N%2==0时,L+1==R

所以 中位数== (A[L]+A[R])/2

这个操作了解以后,代码将会简洁很多。

接下来说查找的思路:

1:暴力,即合并以后查找中位数即可

2:二分思想,A的中位数和B的中位数比较大小,如果A_mid>B_mid说明中位数出现在B的右半部分和A的坐半部分。如此递归下去,知道找到中位数,这里不做详细介绍。

3:也是二分思想,进阶为返回合并后序列中第k个都阔以。其实也是2分思想,但是代码易实现。且功能更多。

大致过程:

访问A中第start+k/2个元素(对应下标-1),访问B中第start+k/2个元素(对应下标-1)。

如果A中的元素大,则更新B的start到刚才访问的下一个元素,递归调用,反之亦然。

直到满足递归条件。

double find_median(const vector<int>&a,const vector<int>&b){
	int len_a=a.size(),len_b=b.size();
	//因为是第k个,k是从1开始的,对应L,R也要+1
	int L=(len_a+len_b-1)/2+1;
	int R=(len_a+len_b)/2+1;
	return (getKth(a,0,b,0,L)+getKth(a,0,b,0,R))/2.0;
}
int getKth(const vector<int>&a,int start1,const vector<int>&b,int start2,int k)
{
	/*递归结束条件*/
	//如果a到头了,返回b中的第k个。
	if(start1>=a.size())return b[start2+k-1];
	//如果b到头,返回a中的第k个。
	if(start2>=b.size())return a[start1+k-1];
	//如果k==1 则返回小的。
	if(k==1)return a[start1]<b[start2]?a[start1]:b[start2];

	int end1=INT_MAX,end2=INT_MAX;//如果star1+k/2-1越界了,自然视为end2<end1,即在b中往后移动k/2;
	if(start1+k/2-1<a.size())end1=a[start1+k/2-1];
	if(start2+k/2-1<b.size())end2=b[start2+k/2-1];

	if(end1<end2)
		return getKth(a,start1+k/2,b,start2,k-k/2);
	else
		return getKth(a,start1,b,start2+k/2,k-k/2);

}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值