题目要求如下:
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
给出两个有序数组,求解数组合集中的中位数。求解中位数是求第k大个数的特例,所以我们下面的讨论以求解第k大个数为例子讨论。
给出这个问题,我们最直接的想法就是给出两个指针分别指向两个数组,哪一个较小哪一个指针后移,知道后移总步数为k,输出即可,但是这样的复杂度是0(m+n)。不满足要求。我们要利用有序这样的条件,第一个指针ia指向数组的第k/2 个位置(也可能是第m个位置,因为短数组可能不到k/2的长度),第二个指针ib指向长数组的第k-ia个位置,这时候比较ia和ib位置的大小,如果A[ia-1]小于B[ib-1],说明A[0]到A[ia-2]间的数字一定小于第k个数字,因此可以首先排除。如果大于的话,说明B[0]到B[bi-2]是小于第k个数字的。就可以排除这两段子段,在接下来的两段新数组中递归调用,就可以求得,当然递归终止是有条件的,在下面的代码中可以明显看到。
class Solution { public: double findMedianSortedArrays(int A[], int m, int B[], int n) { int total = n + m; if (total % 2 == 0) { return (findKth(A, m, B, n, total/2) + findKth(A, m, B, n, total / 2 + 1)) / 2; } else return findKth(A, m, B, n, total / 2 + 1); } double findKth(int a[], int m, int b[], int n, int k) { if (m > n) return findKth(b, n, a, m, k); if (m == 0) return b[k-1]; if (k == 1) return min(a[0], b[0]); int ia = min(k/2, m); int ib = k - ia; if (a[ia-1] < b[ib-1]) return findKth(a+ia, m - ia, b, n, k - ia); else if (a[ia-1] > b[ib-1]) return findKth(a, m, b+ib, n - ib, k - ib); else return a[ia-1]; } };作为总结,再次简单说明步骤:
1.所谓中位数,当总数是奇数时,那么第total/2+1就是中位数,当是偶数时,就是total/2和total/2+1的平均值。
2.确保第一个数组的长度小于第二个数组,通过if (m > n) return findKth(b, n, a, m, k)语句调整。
3.对两个边界情况要做到防御性编程,这也是递归终止的条件。
4.ia要取k/2和m的较小值,这样才能保证不越界,当ia等于m的时候并且还小于B[ib-1],m-ia等于零,就是递归终止条件,在循环中也就是第一个数组连k/2的大小都没有,那么就可以直接排除短数组了,直接取B[]的第k-m个就是第k个数字,也就是说,两个数组是全局有序的。
如果看见有什么错误或者有什么地方写的不对或者你有什么地方看不明白(可能是我表述有问题),请留言指出,我会尽快回复,谢谢!