双有序序列求中位数

1. 题目:

已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列
A 0 A_0 A0​​ , A 1 A_1 A1, … , A N − 1 A_{N-1} AN1 的中位数指 A ( N − 1 ) / 2 A_{(N−1)/2} A(N1)/2的值,即第⌊(N+1)/2⌋个数( A ​ 0 A​_0 A0​​ 为第1个数)

输入格式:

输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的并集序列的中位数

2. 问题描述:

题目的本意就是求两个长度相同的序列的有序交集的中位数,虽然两个序列是有序序列,但是如何求两个序列的合并中位数就很难,而且数据集里也可能有重复的数字!

3. 思路:

例子先行:

输入样例:
5
1 3 5 7 9
2 3 4 5 6
下标:01234
sequnce1:13579
sequence2:23456

我们先看看两个序列的中位数:54 ,比较一下,发现:序列1中位数 比 序列2的大,嗯哼? 而且这两个序列有序

那不就表明 序列1 的 中位数之前的数都比 序列2 中位数在之后的都小吗??(如下)
x x x 2 x x 3 x x x x x 7 x x 9,所以就确立了这样的一个相对排序
那么我们对于 序列1 的 中位数之后的数都比 序列2 中位数在之前的再进行相同的操作,就可以不断地缩小范围。
直到! 上下序列只剩下4个数的时候(即序列1剩2个数,序列2也剩2个数),我们再进行归并排序,这时候的中位数,就是我们要的中位数了

解题过程就是:比较当前两个数组的中位数,中位数大的数组,递归左子数组,中位数小的递归右子数组,

4. 代码:

#include<iostream>

using namespace std;


int middlevalue(int*L, int*R,int L_lindex,int L_rindex,int R_lindex,int R_rindex)
{
	int L_mid = (L_lindex + L_rindex)/2;
	int R_mid = (R_lindex + R_rindex+1)/2; 
	if(L_rindex-L_lindex == 1&& R_rindex - R_lindex==1)
	{
		int count = 0;
		int p1=L_lindex,p2= R_lindex;
		while(count!=2)
		{
			if(L[p1]<R[p2]) 
		  {
			 count++;
			 if(count==2) return L[p1];
			 p1++;
		  }
		  else if(L[p1]>=R[p2])
		  {
		  	 count++; 
		  	 if(count==2) return R[p2]; 
		  	 p2++;
		  }
		}
	
	}
	if(R[R_mid]>L[L_mid])
	{
		middlevalue(L,R,L_mid,L_rindex,R_lindex,R_mid); 
	}
	else if(R[R_mid]<=L[L_mid])
	{
		middlevalue(L,R,L_lindex,L_mid,R_mid, R_rindex);
	}
	
}


int main()
{
	int L[100005] = {0};
	int R[100005]	 ={0};
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>L[i]; 
	}
	for(int i=0;i<n;i++)
	{
		cin>>R[i];
	}
	if(n==1)
	{
		cout<<(L[0]<R[0]?L[0]:R[0]);
	}
	else
	cout<<middlevalue(L, R, 0 , n-1 ,0,n-1);
}

5. 算法实践复杂度分析:

  1. 虽然是两个数组,每次只用一次递归,所以时间复杂度为 l o g 2 n log_2 n log2n
  2. 每次计算两次中位数: 2* l o g 2 n log_2n log2n
  3. 判断是否递归 l o g 2 n log_2n log2n
  4. 最后归并求中位数:while – 2, if – 2 , 内部处理:3*2 +2
所以最后时间复杂度 O( l o g 2 n log_2n log2n

6. 总结:

  1. 自我疑惑:不知道如何证明:不断缩小比较范围后最后归并的中位数就是整个序列的中位数,不具完备性。
  2. 对于int R_mid = (R_lindex + R_rindex + 1)/2; 而int L_mid = (L_lindex + L_rindex)/2;为什么R_mid的计算中要加入1呢,是为了当分割数组是偶数时,两个序列的分割大小能一致
  3. 其实呢,分治的形式有很多,这次收获了使用二分比较,而不是插值,还是蛮惊讶的
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值