这个题描述不麻烦,给定两个有序的整数数组A,B长度分别为M,N,再给定4个长度为K的数组P,Q,R,S。0<=P[i]<=Q[i]< M, 0<=R[i]<=S[i]< N
把A中子数组[P[i],Q[i]]截取出来,B中子数组[R[i],S[i]]截取出来,形成一个数组的中位数一共有K个,求这K个数的中位数。
数据范围N,M [1..10^5]
K [1..10^4]
要求复杂度 时间 O(K*(log(N)+log(M))), 空间 O(k)
为了方便 保证K是奇数,以及Q[i] - P[i] + 1 +S[i] - Q[i] + 1 都是奇数。
分析:
这个题对k个子数组,分别求中位数即可,这就用到了两个有序数组的第k元素的算法。它可以在log(M) + log(N)时间解决。
具体算法:
假设a数组有numa个元素,b数组有umb个元素。如果有一个是空的,则直接返回另外一个一个数组的对应元素。
如果k = 1或者k = numa + numb,分别返回最小和最大的元素。
否则把k分为ka, kb两个部分,ka + kb = k
我们假想一个归并过程,
考虑如果a[ka - 1] <= b[kb - 1],则我们先归并 a[ka - 1],再归并b[kb - 1]。归并完a[ka - 1]之后,归并的总个数小于ka + kb = k,所以a[0..ka - 1] 种不包含第k小的元素。同理,再归并完b[kb - 1]之后,我们归并的元素数一定大于等于ka + kb = k,所以b[kb..N - 1]一定也不包含第k元素。所以a的前半段和b的后半段可以扔掉。a[ka - 1] > b[kb - 1]时,情况对称。
总之,我们每次可以扔掉较小那个元素的数组前面的部分(含本身),和较大那个元素的数组的后面的部分(不含本身)。
这个问题解决之后,我们得到一个长度为C的数组,可以直接排序求中位数,也可以用类似快拍partition的方法期望线性时间求其中位数。
貌似快排的话最后总复杂度是O(k * (log(M) + log(N) + log(K))),不快排应该是O(K * (log(M) + log(N)))。
代码:
int give(int *a,int *b,int numa,int numb,int k) { if (numa == 0) { return b[k - 1]; } if (numb == 0) { return a[k - 1]; } if (k == 1) { return (a[0] < b[0])?a[0]:b[0]; } if (k == numa + numb) { return (a[numa - 1] > b[numb - 1])?a[numa - 1]:b[numb - 1]; } int ka = k * 1. * numa / (numa + numb); if (ka == 0) { ka = 1; } int kb = k - ka; if (kb > numb) { kb = numb; ka = k - kb; } return (a[ka - 1] <= b[kb - 1])?give(a + ka, b, numa - ka, kb, k - ka):give(a, b + kb, ka, numb - kb, k - kb); } int findk(int *a,int n,int k) { int i,j,t; for (i = 1, j = n - 1;; ++i,--j) { for (; (i <= j) && (a[i] < a[0]); ++i) //i <= j 这里可以写(i < n) ; for (; (j >= i) && (a[j] > a[0]); --j) // j >= i 这里可以写(j > 0) ; if (i >= j) { break; } t = a[i]; a[i] = a[j]; a[j] = t; } t = a[0]; a[0] = a[j]; a[j] = t; if (j == k - 1) { return a[j]; } if (j > k - 1) { return findk(a, j , k); } else { return findk(a + j + 1, n - j - 1, k - j - 1); } } int c[10002]; int solution(int A[], int N, int B[], int M, int P[], int Q[], int R[], int S[], int K) { // write your code here... int i; for (i = 0; i < K; ++i) { c[i] = give(A + P[i], B + R[i], Q[i] - P[i] + 1, S[i] - R[i] + 1, (Q[i] - P[i] + 1 + S[i] - R[i] + 1) / 2 + 1); } return findk(c, K , K / 2 + 1); }