题目描述:
一个长度为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的中位数过程以下:数据结构
依次再保留的序列中重复上述过程,直到两个序列中均只含一个元素时为止,较小者即为所求的中位数。测试
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).优化
参考资料:王道数据结构。设计