Median of Two Sorted Arrays
这题挺难的,边界条件老是考虑不清楚。所以在这里记录一下思路,免得将来忘记。
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)).
这题的思路是这样的:
假如a或者b为空,就调用helper1函数,取另一个数组的中位数。记得分清总长度的奇偶,返回结果。
假如a和b都不是空的,则如下考虑:
在最开始的时候,我们取中位数的序号k = (m + n + 1) / 2,也就是说,想要取出两个数组中第k小的元素。这里k是从1开始算的。
接着,我们取ka和kb,作为k在数组a和b中的迭代器。只要我们保持ka+kb=k,那么要找的第k小的元素就始终保持在搜索范围之内。
这里ka和kb也是从1开始计算。
另外还定义了ms和ns,代表a数组和b数组的起始位置——ms和ns之前的元素被二分法排除;
而mt和nt表示当前数组剩余的元素个数——代表ms+mt和ns+nt之后的元素被二分法排除。
当a[ms+ka - 1] < b[ns + kb - 1],就意味着a中剩余元素的前ka个被排除,并且b中剩余元素则剩下kb个。于是,k的值就减去ka,进入下一轮循环。
我们不断地减小k的值,直到k=1.
当循环结束时,k=1,也就是说只要取出a和b中剩余元素中最小的那一个,就是我们要找的第(m+n+1)/2个元素,即中位数。
假如m+n是偶数,那么这时我们要把第k个元素和第k+1个元素取均值作为答案。
好像写的很混乱……
double helper1(int a[], int ms, int m, int k, int odd)
{
if (!m) return 0.;
if (odd) return a[ms + k - 1];
else return (a[ms + k - 1] + a[ms + k]) / 2.;
}
double helper2(int a[], int m, int b[], int n)
{
int ms = 0, ns = 0, mt = m, nt = n; // a和b的起点、剩余长度
int small1 = 0, small2 = 0; // 中位数
int k = (m + n + 1) / 2, ka, kb; // 查找第k个元素的迭代器
bool odd = (m + n) & 1; // m+n是否奇数
if (!m) return helper1(b, 0, n, k, odd); // 假如a是空的,就取b的中位数(第k个)
if (!n) return helper1(a, 0, m, k, odd); // 假如b是空的,就取a的中位数(第k个)
while (k > 1) {
if (mt < nt) { // 为了防止ka、kb越界,先取较小的数组a的中位数作为迭代器ka,再由k-ka得到kb,这样kb肯定也不会越界
ka = (mt + 1) / 2;
kb = k - ka;
} else {
kb = (nt + 1) / 2;
ka = k - kb;
}
if (a[ms + ka - 1] < b[ns + kb - 1]) { // a的值小,把a的前一半和b的后一半排除掉
k -= ka; // 因为a的当前值小,所以排除掉a的前ka个元素,这样下次寻找的时候就找第k-ka个元素
ms += ka; // a的前ka个元素排除掉,因此a数组的起始位置右移ka个
mt -= ka; // a数组的剩余元素个数减去ka
nt = kb; // b数组只剩kb个元素
} else {
k -= kb;
ns += kb;
nt -= kb;
mt = ka;
}
if (!mt) return helper1(b, ns, nt, k, odd); // 发现a已经排除完了,就只要在b里面找第k个元素
if (!nt) return helper1(a, ms, mt, k, odd);
} // 循环结束,此时的k必定等于1
if (a[ms] < b[ns]) { //找出a和b剩余元素中的最小值和次小值
small1 = a[ms];
small2 = b[ns];
if (ms < m - 1) small2 = std::min(b[ns], a[ms + 1]);
} else {
small1 = b[ns];
small2 = a[ms];
if (ns < n - 1) small2 = std::min(a[ms], b[ns + 1]);
}
if (odd) return small1; // 返回中位数
else return (small1 + small2) / 2.;
}
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n) {
// Note: The Solution object is instantiated only once and is reused by each test case.
return helper2(A, m, B, n);
}
};