时间和空间复杂度最少的求两个升序数组的中位数

    题目描述:
             一个长度为L的升序S,处在L/2向下取整处的位置的数称为S的中位数。
             现求两个等长的两个升序序列A和B的中位数。 

    分析:当然这题如果不要求最高效的话,可以完全重新开辟一个2倍长度的数组C,然后将A,B数组合并到C中,然后得其(L/2 - 1)处的值,即可。但空间复杂度较高为O(n),并且合并的时间复杂也为O(n),所以自己又进一步改进了一下,将空间复杂度降到了O(1),但时间复杂度依旧是O(n).下面给出代码:

#include<stdio.h>
int M_serach(int s1[],int s2[]){
	int mid=0;
	int len = 5;
	int i=0,j=0;
	while(i<len&&j<len){//其实就是模拟合并的过程只是不需要将其装入C数组中了
		if(s1[i]>s2[j]) {
			j++;
			mid++;
			if(mid == len-1) printf("%d\n",s1[i]);
		}else{
			i++;
			mid++;
			if(mid == len-1) {
				printf("%d\n",s2[j]);
			}
		}
	}
}
//为了方便,我就任意取了几组测试数据
int s1[] = {1,3,5,7,9};
int s2[] = {2,4,6,8,20};
int main(){
	M_serach(s1,s2);
	return 0; 
} 

可以进一步优化时间复杂度,主要是借助二分的思想,算法的基本设计思想如下:分别求两个升序的序列A,B的中位数,设为a和b,求序列A,B的中位数过程如下:

  1. 若a=b,则a或b即为所求中位数,算法结束。
  2. 若a<b,则舍弃序列A中较小的一半,同时舍弃序列B中较大的一半,要求两次舍弃的长度相等。
  3. 若b>a,则舍弃序列B中较小的一半,同时舍弃序列A中较大的一半,要求两次舍弃的长度相等。

依次再保留的序列中重复上述过程,直到两个序列中均只含一个元素时为止,较小者即为所求的中位数。

int M_Search(int A[],int B[],int n){
	int s1=0;d1=n-1,m1,s2=0,d2=n-1,m2;
	//分别表示序列A和B的首位数,末尾数和中位数。
	while(s1!=d1||s2!=d2){//s1==d1&&s2==d2
		m1 = (s1+d1)/2;
		m2 = (s2+d2)/2;
		if(A[m1]==B[m2]) return A[m1];
		if(A[m1]<B[m2]){
			if((s1+d1)%2==0){  //元素个数为奇数个((d1-s1+1)%2==0判断的为偶数==>(d1-s1)%2==0奇数又因
                               // 为 (s1+s1+d1-s1+1)%2等价即(s1+d1+1)%2 ==>(s1+d1)%2==0为奇数) 
				s1 = m1;      //舍弃A中间点以前的部分且保留中间点 
				d2 = m2;	 //舍弃B中间点后面的部分且保留中间点 
			}else{			//元素个数为偶数个
				s1 = m1+1; //舍弃A中间点及中间点以前的部分 
				d2 = m2;  //舍弃B中间点以后部分且保留中间点 
			}
		}else{
			if((s2+d2)%2==0){  //元素个数为奇数个 
				s2 = m2;      //舍弃B中间点以前的部分且保留中间点 
				d1 = m1;	 //舍弃A中间点后面的部分且保留中间点 
			}else{			//元素个数为偶数个
				s2 = m2+1; //舍弃B中间点及中间点以前的部分 
				d1 = m1;  //舍弃A中间点以后部分且保留中间点 
			}
		} 
	} 
	return A[s1]<B[s2]?A[s1]:B[s2];
}

可以手动模拟一下上述算法,为什么最后去较小者,是因为我们的中位数取得是L/2向下取整的位置,最后的时间复杂为O(logn),空间复杂度为O(1).

参考资料:王道数据结构。

转载于:https://my.oschina.net/u/2484601/blog/808302

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值