1. 如果两个数组不等长
int findMedian(int a[],int alen, int b[], int blen) {
int amid = alen /2;
int bmid = blen / 2;
int low = min(amid,bmid);
if (alen == 1) {
if (blen % 2 == 0) {
if (a[0] >= b[bmid])//b[bmid]是上中位数
return b[bmid];
else if (a[0] <= b[bmid-1])
return b[bmid - 1];
else//a[0]在上下中位数之间
return a[0];
}
else {
return b[bmid];
}
}
if (blen == 1 ) {
if (alen % 2 == 0) {
if (b[0] >= a[amid])
return a[amid];
if(b[0]<= a[amid-1])
return a[amid-1];
else
return b[0];
}
else
return a[amid];
}
if (a[amid] == b[bmid])
return a[amid];
if (a[amid] > b[bmid])
return findMedian(a,alen - low,b+low,blen -low);//不能删除中点,中点可能就是中位数
else
return findMedian(a+low,alen - low,b,blen - low);
}
int main() {
int a[] = {1,2,3,4,5,6,7,8};
int b[] = {9,10};
cout<<findMedian(a,8,b,2)<<endl;
return 0;
}
非递归版本
int findMid(int *a, int abeg,int aend, int *b, int bbeg,int bend) {
while (abeg != aend || bbeg != bend) {
int mid1 = (abeg + aend)/2;
int mid2 = (bbeg + bend)/2;
if (a[mid1]== b[mid2])
return a[mid1];
if (abeg == aend && bbeg == bend)
return a[mid1] < b[mid2] ? a[mid1] : b[mid2];//下中位数
if (abeg == aend) {
if ( (bbeg + bend) % 2 == 0){//b有奇数个元素
if (a[mid1] >= b[mid2])
return b[mid2];
else {
if (b[mid2 - 1] <= a[mid1])
return a[mid1];
else
return b[mid2 - 1];
}
}
else {
if (a[mid1] <= b[mid2])
return b[mid2];
else {
if (a[mid1] >= b[mid2 + 1])
return b[mid2 + 1];
else
return a[mid1];
}
}
}
if (bbeg == bend) {
if ( (abeg + aend) % 2 == 0){//a有奇数个元素
if (a[mid1] <= b[mid2])
return a[mid1];
else {
if (a[mid1 - 1] <= b[mid2])
return b[mid2];
else
return a[mid1 - 1];
}
}
else {
if (a[mid1] >= b[mid2])
return a[mid1];
else {
if (b[mid2] >= a[mid1 + 1])
return a[mid1 + 1];
else
return b[mid2];
}
}
}
int alen = aend - abeg + 1;
int blen = bend - bbeg + 1;
int minlen = min(alen,blen)/2;
if (a[mid1] < b[mid2]) {
abeg += minlen;
bend -= minlen;
}
else {
aend -= minlen;
bbeg += minlen;
}
}
}
至于为什么要剪去较小的那部分,请参看这个图
两段都减去一半,这时剩下的两段求中点就不再是中位数了。
可以这样想象,比如这两段已经合并成一段了,其中位数在中间位置,如果在开始的时候删除n个,在结束的时候删除n个,其中位数还是在中间位置;
但是,如果开始的时候删除n个,在结束的时候删除m个,则中位数就不在中间位置了。
2. 如果等长求中位数
// 两个长度相等的有序数组寻找中位数
int Find_Media_Equal_Length(int a[] , int b[] , int length)
{
if(length == 1)
{
return a[0] > b[0] ? b[0] : a[0];
}
int mid = (length-1)/2; //奇数就取中间的,偶数则去坐标小的
if(a[mid] == b[mid])
return a[mid];
else if(a[mid] < b[mid])
{
return Find_Media_Equal_Length(&a[length-mid-1] , &b[0] , mid+1); //偶数则取剩下的length/2,奇数则取剩下的length/2+1
//return Find_Media_Equal_Length(a+length-mid-1 , b , mid+1);
}
else
{
return Find_Media_Equal_Length(&a[0] , &b[length-mid-1] , mid+1);
//return Find_Media_Equal_Length(a , b+length-mid-1 , mid+1);
}
}
3. 等长求第i个
4. 不等长求第i个
1 2 3 6 7 8 14 *16* 18 19 20 23 27 28 33
|<--- A1 --->| a |<------- A2 ------->|
4 5 9 10 11 *12* 14 17 22 24 29
|<-- B1 -->| b |<---- B2 ---->|
分为四段,每次删除一段
int FindTheKth(int a[],int b[],int aLeft, int aRight, int bLeft, int bRight, int k) {
int aMid = (aLeft + aRight) / 2, bMid = (bLeft + bRight) / 2;
if (aLeft > aRight) return b[bLeft+k-1];
if (bLeft > bRight) return a[aLeft+k-1];
if (a[aMid] <= b[bMid]) {
if (k <= (aMid - aLeft) + (bMid - bLeft) + 1) {
return FindTheKth(a,b,aLeft, aRight, bLeft, bMid-1, k);//bMid-1 有些不妥,如果第k个数就是b[bMide]呢?所以不能去掉bMid,但是得在前面判断只有一个元素的情况
} else {
return FindTheKth(a,b,aMid+1, aRight, bLeft, bRight, k-(aMid-aLeft)-1);
}
} else {
if (k <= (aMid - aLeft) + (bMid - bLeft) + 1) {
return FindTheKth(a,b,aLeft, aMid-1, bLeft, bRight, k);
} else {
return FindTheKth(a,b,aLeft, aRight, bMid+1, bRight, k-(bMid-bLeft)-1);
}
}
return -1;
}