看了题解才会做。题解是把取中位数的问题转化为了取第k小的数的问题。
题解的思路是:先判断两数组长度和m+n是奇数还是偶数。奇数则直接取两数组的第(m+n) / 2 + 1小的数,偶数则取第(m+n) / 2和第(m+n) / 2 + 1小的数取平均值。
取第k小的数的办法是:给定两数组a(长度为m)和b(长度为n)和k。
若m>n则调换两个数组;若m=0,则意味着a数组空,第k小在b里,直接返回b[k - 1];若k=1,则第k小必然在a[0]和b[0]中,返回a[0]和b[0]中的最小值。
若上述条件都不符合,则m>=1且k>=2,a不为空且不确定第k小的数在a还是在b。那么就要想办法把a和b的前面的一些元素去掉。
设去掉a的前x个数,那就要使x尽可能靠近k / 2且不能超过m,所以x=min(k / 2, m)。然后设去掉b的前y个数,y=k - x。
比较a[x - 1]和b[y - 1]。若前者更大,则b的前y个数都不可能是第k小的数,下一个递归去比较a(长度m)和b+y(长度为n - y);若后者更大,则a的前x个数都不可能是第k小的数,一个递归去比较a + x(长度m - x)和b(长度为n);若相等,则a[x - 1]和b[y - 1]都是第k小的数,随便return一个。
看答案前想了很多办法,花了2个小时都没做出来,想想还是放弃了。感觉很难。
double findKth(int a[], int m, int b[], int n, int k) {
//always assume that m is equal or smaller than n
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]);
//divide k into two parts
int x = min(k / 2, m), y = k - x;
if (a[x - 1] < b[y - 1])
return findKth(a + x, m - x, b, n, k - x);
else if (a[x - 1] > b[y - 1])
return findKth(a, m, b + y, n - y, k - y);
else
return a[x - 1];
}
class Solution
{
public:
double find(int A[], int m, int B[], int n)
{
int total = m + n;
if (total & 0x1)
return findKth(A, m, B, n, total / 2 + 1);
else
return (findKth(A, m, B, n, total / 2) +
findKth(A, m, B, n, total / 2 + 1)) / 2;
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int l1 = nums1.size(), l2 = nums2.size();
int *a = new int[l1], *b = new int[l2];
for (int i = 0; i < l1; ++i) a[i] = nums1[i];
for (int i = 0; i < l2; ++i) b[i] = nums2[i];
return find(a, l1, b, l2);
}
};