第一题来自于《算法导论》第九章习题 9.3-8. 已知两个已排序数组X[n], Y[n](假设升序),问在时间O(lgn)内找到全部2n个数中的中位数。
给了提示时间O(lgn),那么必定使用二分查找。这道题的“梗”在于如何处理两个已排序数组。我们有总共2n个数,偶数,那么全局的中位数来自于两个数a,b,在排好序的2n个数中,它们以上(比它们大)和以下(比它们小)应该各有n-1个数。令a > b,假设a==X[i], 即数组X 中,a以下有i个数小于a。对于b,有两个可能来源,X[i-1] 或者Y[n-1-i],这里Y[n-1-i]是数组Y中比a小的数中最大的一个。
综上所述,我们的二分查找逻辑如下:首先在数组X中对于区间[v,u), 由i=(v+u)/2寻找X[i] ,对于j=n-1-i, 检查 if Y[j+1] > X[i] && Y[j] < X[i],否则通过增大或者缩小i来反向改变j。如果这样的a不在X[]中,则对于数组Y重复以上处理。
实现代码如下,注意数组边界情况,比如i==0 或者i==n-1
bool findmediansingle(int* A, int* B, int n, double& res){ // find total median in array A int u=n, v=0; while(v<u){ //[v,u) int i = (v+u)/2; int j = n-1-i; //index in B[] if(A[i] <= B[j]){ //we need to find the middle two elements among the total merged array if(j==0 || A[i] >= B[j-1]){ //all elements less than A[i] and B[j] adds up to mid int low = A[i]; //since we focus binary cursor on i, A[i] is fixed as floor of the two middle int high = B[j]; if(i<n-1 && A[i+1]<B[j]){ //A[i+1] is closer to A[i] then B[j] high = A[i+1]; } res = (double)(low + high)/2; return true; }else{ v=i+1; //enlarge i to reduce j