已知有兩個等長的非降序序列S1, S2, 設計函數求S1與S2並集的中位數。有序序列ios
A0, A1, … ,AN−1的中位數指A(N−1)/2的值,即第⌊(N+1)/2⌋個數(A 0爲第1個數)算法
輸入格式:數組
輸入分三行。第一行給出序列的公共長度N(0<N≤100000),隨後每行輸入一個序列的信息,即N個非降序排列的整數。數字用空格間隔。函數
輸出格式:spa
在一行中輸出兩個輸入序列的並集序列的中位數設計
題目的本意就是求兩個長度相同的序列的有序交集的中位數,雖然兩個序列是有序序列,可是如何求兩個序列的合併中位數就很難,並且數據集裏也可能有重複的數字!排序
例子先行:遞歸
輸入樣例:ci
5io
1 3 5 7 9
2 3 4 5 6
下標: 0 1 2 3 4
sequnce1: 1 3 5 7 9
sequence2: 2 3 4 5 6
咱們先看看兩個序列的中位數:5 和 4 ,比較一下,發現:序列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個數),咱們再進行歸併排序,這時候的中位數,就是咱們要的中位數了
解題過程就是:比較當前兩個數組的中位數,中位數大的數組,遞歸左子數組,中位數小的遞歸右子數組,
#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);
}
1. 雖然是兩個數組,每次只用一次遞歸,因此時間複雜度爲 log2n
2 .每次計算兩次中位數: 2*log2n
3. 判斷是否遞歸 log2n
4. 最後歸併求中位數:while – 2, if – 2 , 內部處理:3*2 +2
5. 因此最後時間複雜度 O(log2n)
6. 總結:
自我疑惑:不知道如何證實:不斷縮小比較範圍後最後歸併的中位數就是整個序列的中位數,不具完備性。
對於int R_mid = (R_lindex + R_rindex + 1)/2; 而int L_mid = (L_lindex + L_rindex)/2;爲何R_mid的計算中要加入1呢,是爲了當分割數組是偶數時,兩個序列的分割大小能一致
其實呢,分治的形式有不少,此次收穫了使用二分比較,而不是插值,仍是蠻驚訝的