9.3-8 设X[1…n]和Y[1…n]为两个数组,每个都包含n个有序的元素,请设计一个 O ( l g n ) O(lgn) O(lgn)时间的算法找出数组X和Y中所有2n个元素的中位数。
下面假设中位数(低中位数,数组长度偶数时较小的那个)在数组 X X X中。如果要求中间两个数的均值,只需要在该基础之上修改一点就好。
a、 X [ k ] = m X[k]=m X[k]=m为中位数,对于数组 X X X,有 k k k个元素小于等于 X [ k ] X[k] X[k],同时有 n − k n-k n−k个元素大于等于 X [ k ] X[k] X[k]。当两个数组合并有序时,对于中位数来说,共有 n n n个元素小于等于 X [ k ] X[k] X[k],n个元素大于等于 X [ k ] X[k] X[k]。那么对于数组 Y Y Y来说,有 n − k n-k n−k个元素小于等于 X [ k ] X[k] X[k], n − ( n − k ) = k n-(n-k)=k n−(n−k)=k个元素大于等于 X [ k ] X[k] X[k]。那么就存在以下不等式:
Y [ n − k ] ≤ X [ k ] ≤ Y [ n − k + 1 ] , 1 ≤ k < n Y[n-k] \leq X[k] \leq Y[n-k+1],1 \leq k < n Y[n−k]≤X[k]≤Y[n−k+1],1≤k<n
b、 若 X [ k ] 若X[k] 若X[k]不是中位数。且中位数为 X [ k ′ ]   ( 1 ≤ k ′ < k < n ) X[k'] \,(1 \leq k' < k < n) X[k′](1≤k′<k<n),那么就有:
Y [ n − k ′ ] ≤ X [ k ′ ] ≤ Y [ n − k ′ + 1 ] Y[n-k'] \leq X[k'] \leq Y[n-k'+1] Y[n−k′]≤X[k′]≤Y[n−k′+1]
那么对于
X
[
k
]
X[k]
X[k]来说,有:
Y
[
n
−
k
+
1
]
≤
Y
[
n
−
k
′
]
≤
X
[
k
′
]
<
X
[
k
]
Y
[
n
−
k
+
1
]
<
X
[
k
]
\begin{aligned} Y[n-k+1] &\leq Y[n-k'] \leq X[k'] < X[k] \\ Y[n-k+1] &< X[k] \end{aligned}
Y[n−k+1]Y[n−k+1]≤Y[n−k′]≤X[k′]<X[k]<X[k]
c、
若
X
[
k
]
若X[k]
若X[k]不是中位数。且中位数为
X
[
k
′
]
(
1
≤
k
<
k
′
<
n
)
X[k'] \ (1 \leq k < k' < n)
X[k′] (1≤k<k′<n),那么就有:
Y
[
n
−
k
′
]
≤
X
[
k
′
]
≤
Y
[
n
−
k
′
+
1
]
Y[n-k'] \leq X[k'] \leq Y[n-k'+1]
Y[n−k′]≤X[k′]≤Y[n−k′+1]
那么对于
X
[
k
]
X[k]
X[k]来说,有:
X
[
k
]
<
X
[
k
′
]
≤
Y
[
n
−
k
′
+
1
]
≤
Y
[
n
−
k
]
X
[
k
]
<
Y
[
n
−
k
]
\begin{aligned} X[k] &< X[k'] \leq Y[n-k'+1] \leq Y[n-k] \\ X[k] &< Y[n-k] \end{aligned}
X[k]X[k]<X[k′]≤Y[n−k′+1]≤Y[n−k]<Y[n−k]
d、在递归的过程中,我们要注意一个递归的一个边界问题,在实际的编程中,对于数组 A [ L , . . R ] , 1 ≤ L ≤ R ≤ n A[L,..R],1 \leq L \leq R \leq n A[L,..R],1≤L≤R≤n。我们取 k = ( L + R ) / 2 , k ∈ [ 1 , n ] k=(L+R)/2,k \in [1,n] k=(L+R)/2,k∈[1,n], 当 k = n k=n k=n时,那么对于上面三种情况会出现 Y [ n − k ] = Y [ 0 ] Y[n-k]=Y[0] Y[n−k]=Y[0]是一个空数组,对于这种情况,其实只需判断 X [ k ] = X [ n ] ≤ Y [ 1 ] X[k]=X[n] \leq Y[1] X[k]=X[n]≤Y[1]。
利用上面的性质,就可以在 O ( 1 ) O(1) O(1)的时间内判断 X [ k ] X[k] X[k]是否时中位数。对于一个数组区间 X [ L , R ] X[L,R] X[L,R]。我们采用二分的思想,取中点 k = ( L + R ) / 2 k=(L+R)/2 k=(L+R)/2,判断上面的条件,如果满足条件a或d,那么 X [ k ] X[k] X[k]就是中位数,如果是条件b,那么说明 k k k偏大,我们在左子区间继续二分查找,否则为条件c,我们在右子区间继续二分查找。这样的一个二分查找过程的时间复杂度为 Θ ( l g n ) \Theta(lgn) Θ(lgn)。
上面给出性质的是假设中位数在数组 X X X的分析,如果中位数不在数组 X X X中,在查找的过程中到达边界而不满足 X [ k ] X[k] X[k]为中位数的a条件,我们可以返回一个标志如NOTFIND。此时中位数一定在数组 Y Y Y中,我们进行同样的操作。最差情况下进行 2 l g n 2lgn 2lgn次查找。时间复杂度仍为为 Θ ( l g n ) \Theta(lgn) Θ(lgn)。
下面是伪代码:
Two-Array-Medium(X,Y)
n <-- X.length //与数组Y长度相同
medium = Find-Medium(X,Y,1,n,n)//先尝试在数组X查找
if medium = NOTFIND//未找到,在Y数组查找
medium = Find-Medium(Y,X,1,n,n)
return medium
Find-Medium(A,B,low,high,n)
if low > high
return NOTFIND
else
k = (high+low)/2
if k=n and A[n]<=B[1]
return A[n]
elseif k < n and B[n-k] <= A[k] <= B[n-k+1]
return A[k]
elseif B[n-k+1] < A[k]
return Find-Medium(A,B,low,k-1,n)
else
return Find-Medium(A,B,k+1,high,n)
实际编程中,数组从0开始稍微改动下即可。
#include<iostream>
#include<ctime>
#include<random>
#include<algorithm>
using namespace std;
#define LEN 5
#define NOTFIND 0x3f3f3f3f
//参数n为数组长度,此时边界为n-1
int findMedium(int A[],int B[],int L,int R,int n)
{
if(L>R)
return NOTFIND;
int k=(L+R)/2;
// k=n-1时要独立一个分支,否则第二个if会越界
if(k==(n-1)&&A[k]<=B[0])
return A[k];
else if(k<(n-1)&&B[n-k-2]<=A[k]&&A[k]<=B[n-k-1])
return A[k];
else if(B[n-k-1]<A[k])
return findMedium(A,B,L,k-1,n);
else
return findMedium(A,B,k+1,R,n);
}
int TwoArrayMedium(int A[],int B[],int len)
{
int ret=NOTFIND;
if((ret=findMedium(A,B,0,len-1,len))==NOTFIND)
ret=findMedium(B,A,0,len-1,len);//不在数组A,继续在B中查找
return ret;
}
template<typename T,unsigned N>
void getRandomArray(T (&arr)[N])
{
//随机生成2000以内的随机数
static default_random_engine e(time(nullptr));
static uniform_int_distribution<T> d(0,2000);
for(auto &i:arr)
i=d(e);
sort(arr,arr+N);//数组排序
}
int main()
{
int A[LEN];
int B[LEN];
getRandomArray(A);
getRandomArray(B);
int C[2*LEN];
copy(A,A+LEN,C);
copy(B,B+LEN,C+LEN);
sort(C,C+2*LEN);
for(auto i:C)
cout << i << " ";
cout << endl;
cout << "中位数为:" << TwoArrayMedium(A,B,LEN) << endl;
return 0;
}
这个问题我只求了低中位数,因为数组总长度为 2 n 2n 2n恒为偶数,因此如果要求中间两个数的均值。只需要在上面代码的基础上稍微改下,加上 k + 1 k+1 k+1位置的数,然后除2即可达到。(注意:如果k求出是X数组的最后一位,那么高中位数在数组Y中)。