There are two sorted arrays nums1 and nums2 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)).
Example 1:
nums1 = [1, 3] nums2 = [2] The median is 2.0
=======================================
题目要求O(logn)的时间求解问题,很容易想到是二分搜索的方法来做,但是不同于一般的二分,这里是有两个各自有序的数组,所以需要寻找额外的约束条件。
要求的是中位数,中位数最重要的性质是位于中间,也就是刚好将数组平分,左侧长度等于右侧长度。这是一个很重要的性质,有了这个性质,我只要二分其中一个数组的分割点,就可以求出另一数组的分割点。
再来看如何更新左界和右界使得算法进行下去。假设两数组名为A和B,长度分别为m和n,现在二分数组A的边界i,由约束条件中位数两侧长度相等,可以求得B的边界j。当i和j是正确的边界时,应该有A[i-1] <= B[j] and B[j-1] <= A[i]。如果B[j-1] > A[i],则说明j取大了,i取小了。如果A[i-1] > B[j]说明i取大了。按照这样的规则则可以正确地二分出结果,需要注意边界条件如i=0,i=m此时不存在A[i-1]或A[i],这种情况也应该视为满足了条件。
还有一点需要注意的是,题目给了两个数组,应该二分长度较小的那个数组,否则会出现j超出了范围的问题,比如,A的长度为10,B的长度为2,当二分到i=2时,得到j=4,此时访问B[j-1]出现运行错误。(我在这里WA了两次)
最后是代码:
class Solution {
public:
double findMedianSortedArrays(vector<int>& A, vector<int>& B) {
int m = A.size();
int n = B.size();
vector<int> &nums1 = m > n ? B : A;
vector<int> &nums2 = m > n ? A : B;
if (m > n) {
int tmp = m;
m = n;
n = tmp;
}
int lo = 0, hi = m, half = (m + n + 1) / 2;
int i, j;
while (lo <= hi) {
i = (lo + hi) / 2;
j = half - i;
if (j > 0 && i < m && nums2[j-1] > nums1[i]) {
lo = i+1;
} else if (i > 0 && j < n && nums1[i-1] > nums2[j]) {
hi = i-1;
} else {
break;
}
}
int max_l, min_r;
if (i == 0) max_l = nums2[j-1];
else if (j == 0) max_l = nums1[i-1];
else max_l = max(nums1[i-1], nums2[j-1]);
if ((m+n) & 1) return max_l;
if (i == m) min_r = nums2[j];
else if (j == n) min_r = nums1[i];
else min_r = min(nums1[i], nums2[j]);
return (max_l + min_r) / 2.0;
}
};