時間和空間複雜度最少的求兩個升序數組的中位數

    題目描述:
             一個長度爲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).優化

參考資料:王道數據結構。設計

相關文章
相關標籤/搜索