题目
C++ solution
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
if (m <= n)
{
return find(m, n, nums1, nums2);
} else {
return find(n, m, nums2, nums1);
}
}
double find(int m, int n, vector<int>& nums1, vector<int>& nums2) {
int iMin = 0, iMax = m, midPos = (m + n +1) / 2;
while (iMin <= iMax) {
int i = (iMin + iMax) / 2;
int j = midPos - i;
if (i < iMax && nums2[j - 1] > nums1[i]) // i is too small
{
iMin = i + 1;
}
else if (i > iMin && nums1[i - 1] > nums2[j]) // i is too big
{
iMax = i - 1;
}
else
{
int maxLeft = 0;
if (i == 0) maxLeft = nums2[j -1];
else if (j == 0) maxLeft = nums1[i - 1];
else maxLeft = nums2[j - 1] > nums1[i - 1] ? nums2[j - 1] : nums1[i - 1];
if ((m + n) % 2 == 1) return maxLeft;
int minRight = 0;
if (i == m) minRight = nums2[j];
else if (j == n) minRight = nums1[i];
else minRight = nums2[j] < nums1[i] ? nums2[j] : nums1[i];
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
};
简要题解
中位数(median):将集合中的数进行排序,最中间的那个数或两个数的平均数即是中位数。
题中两个有序数组(长度分别为m, n),将所有数以中位数分割为左半部分(left_part)和右半部分(right_part)
left_part | right_part |
---|---|
nums1[0], nums1[1], … , nums1[i-1] | nums1[i], nums1[i+1], … , nums1[m-1] |
nums2[0], nums2[1], … , nums2[j-1] | nums2[i], nums2[i+1], … , nums2[n-1] |
其中
i = 0 ~ m, j = 0 ~ n
len(left_part) = len(right_part)
max(left_part) <= min(right_part)
median = (max(left_part) + min(right_part)) / 2 (m+n为偶数)
median = max(left_part) (m+n为奇数)
由上性质,可得
i + j = m - i + n - j (or: m - i + n - j + 1)
即 i = 0 ~ m, j = (m + n + 1) / 2 - i;(由于整数除运算舍去小数部分,两种情况可以合一)
注意:为保证 j 不为负,必须 m <= n;若 m > n,只需互换,计算完全相同
nums2[j-1] <= nums1[i],nums1[i-1] <= nums2[j]
考虑特殊情况
当 i = 0, i = m, j = 0, j = m,即意味着 nums1[i-1], nums1[i], nums2[j-1], nums2[j] 可能不存在。解决办法很简单,把相应的限制条件(nums2[j-1] <= nums1[i] 或 nums1[i-1] <= nums2[j])忽略即可。
通过以上分析,可以总结出每次搜索只有三种情况
注意:j 的值随 i的变化而变化,所以仅需考虑 i 如何改变来得出结果。且 i < m,则 j > 0;i > 0,则 j < n。
// 1. i 取值较小,需增大
i < m && nums2[j-1] > nums1[i]
// 2. i 取值较大, 需减小
i > 0 && nums1[i-1] > nums2[j]
// 3. i 取值刚好,结束搜索,计算结果并返回
( j == 0 || i == m || nums2[j-1] <= nums1[i]) && (i == 0 || j == n || nums1[i-1] <= nums2[j])
采用二分搜索,即可搜索得到 i 的目标值,由 i 值计算得到 j 值,再计算除两个数组的中位数,得到答案。