在两个长度相等的排序数组中找到上中位数
题目描述
给定两个有序数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。
上中位数:假设递增序列长度为n,若n为奇数,则上中位数为第n/2+1个数;否则为第n个数
[要求]
时间复杂度为 O ( l o g N ) O(logN) O(logN),额外空间复杂度为 O ( 1 ) O(1) O(1)
输入描述:
第一行一个整数N,表示数组大小。
接下来一行N个整数,表示arr1内的元素
再接下来一行N个整数,表示arr内的元素
输出描述:
输出一个整数表示答案
示例1
输入
4
1 2 3 4
3 4 5 6
输出
3
说明
总共有8个数,上中位数是第4小的数,所以返回3。
示例2
输入
3
0 1 2
3 4 5
输出
2
说明
总共有6个数,那么上中位数是第3小的数,所以返回2
备注:
1
⩽
N
⩽
1
0
5
1 \leqslant N \leqslant 10^5
1⩽N⩽105
0
⩽
a
r
r
1
i
,
a
r
r
2
i
⩽
1
0
9
0 \leqslant arr_{1_{i}}, arr_{2_{i}} \leqslant 10^9
0⩽arr1i,arr2i⩽109
题解:
首先可以确定是二分,我们重新定义一下问题:在 a1[s1…e1] 和 a2[s2…e2] 上寻找两段数组的上中位数,并且两段数组长度相等。
-
若每个数组只有一个元素,较小的那个就是整体的上中位数,相等的话,随便返回哪一个都行;
-
若数组中不止一个元素,找到两个数组的中间位置 mid1 和 mid2 ,分情况讨论:
- 若 a1[mid1] == a2[mid2] ,无论数组元素个数是奇数还是偶数,这两个数都是整体的上中位数,返回其中一个即可
- 若 a1[mid1] > a2[mid2],分元素个数奇偶性讨论:
- 若元素个数为奇数,a1 中 mid1 位置以后的元素都不可能是整体的上中位数,a2 中 mid2 位置以前的元素都不可能是整体的上中位数,所以只需要考虑 a1[s1…mid1] 和 a2[mid2…e2] ,两部分元素个数相同;
- 若元素个数为偶数,a1 中 mid1 位置以后的元素都不可能是整体的上中位数, a2 中 mid2 位置以后包括 mid2 位置,都不可能是整体的上中位数,所以只需要考虑 a1[s1…mid1] 和 a2[mid2+1…e2] ,两部分元素个数相同
- 若 a1[mid1] < a2[mid2] ,分析同 2
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100000;
int n;
int a[N];
int b[N];
int main(void) {
scanf("%d", &n);
for ( int i = 0; i < n; ++i )
scanf("%d", a + i);
for ( int i = 0; i < n; ++i )
scanf("%d", b + i);
if ( a[n - 1] <= b[0] || b[n - 1] <= a[0]) {
printf("%d\n", min( a[n - 1], b[n - 1] ) );
return 0;
}
int sa = 0, ea = n - 1;
int sb = 0, eb = n - 1;
int ma, mb, ret = -1;
while ( sa < ea ) {
ma = sa + ea >> 1;
mb = sb + eb >> 1;
if ( a[ma] == b[mb] ) {
ret = a[ma];
break;
}
int bit = ((ea - sa + 1) & 1) ^ 1;
if ( a[ma] > b[mb] ) {
ea = ma;
sb = mb + bit;
} else {
eb = mb;
sa = ma + bit;
}
}
if ( ret == -1 ) ret = min( a[sa], b[sb] );
printf("%d\n", ret);
return 0;
}