Difficulty:Hard
Description
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
Example 2
nums1 = [1, 2]
nums2 = [3, 4]The median is (2 + 3)/2 = 2.5
Solution
思路
该题目的解决思路和代码都有给出:
https://leetcode.com/problems/median-of-two-sorted-arrays/solution/
这里主要说说做题时我遇到的问题和难点。
我利用二分法,先设好imin
和imax
的值,令
i=imin+imax2
. 若i
偏大了,则令imax= i - 1
, 再令
i=imin+imax2
.
但这样的结果是超时的。看过Solution
的Java代码,原来在i
偏大时,他令imax = imax - 1
, 再令
i=imin+imax2
. 这样不超时。
后者比前者快的原因暂不清楚,没有研究过testcase。
掌握好解题的大致思路后,我认为尚存的难点是边界问题和访问过界,即在i = 0
时不能访问nums1[i - 1]
, 在i = m
时不能访问nums1[i]
. 这些问题看似简单,但在解决这些问题时总是容易顾此失彼。
代码
Accepted. 52ms. Beats 67% of cpp submissions.
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) nums1.swap(nums2);
int m = nums1.size(), n = nums2.size();
int imin = 0, imax = m, halflen = (m + n + 1) / 2;
int i, j;
while (imin <= imax) {
// 这里保证左右两边数量相等
// 即len(nums1[0~i-1])+len(nums2[0~j-1]) == len(nums1[i~m-1])+len(nums2[j~n-1])
i = (imin + imax) / 2;
j = halflen - i;
// 要想找到中位数,
// 只要满足nums1[i-1] <= nums2[j] && nums2[j-1] <= nums1[i]两个条件即可.
// 若nums1[i-1] > nums2[j], 说明i太大,要减小它.
// 若nums2[j-1] > nums1[i], 说明i太小,要增大它.
// 遇到边界时,
// 对于nums1[i-1] <= nums2[j], 若i == 0, 说明nums1左半部分是空的,
// 则不需要比较它们.
// 同理对于nums2[j-1] <= nums1[i], 若i == m, 说明nums1右半部分是空的,不需比较它们.
// 由于前面已保证m <= n, 故访问nums2[j]时不会越界, 不需考虑j == 0或n的情况.
if (i != 0 && nums1[i - 1] > nums2[j]) { // i太大,要减小i
--imax;
}
else if (i != m && nums2[j - 1] > nums1[i]) { // i太小,要增大i
++imin;
}
else { // i is perfect, 计算中位数
int leftmax, rightmin;
if (i == 0) leftmax = nums2[j - 1];
else if (j == 0) leftmax = nums1[i - 1];
else leftmax = nums1[i - 1] >= nums2[j - 1] ? nums1[i - 1] : nums2[j - 1];
if (i == m) rightmin = nums2[j];
else if (j == n) rightmin = nums1[i];
else rightmin = nums1[i] < nums2[j] ? nums1[i] : nums2[j];
if ((m + n) % 2 == 1) return leftmax;
else return (double(leftmax) + double(rightmin)) / double(2);
}
}
}
};