题目:
思路:
自己做的时候没有符合O(log(m+n))的思路,参考了discuss的解答。
首先,我们的目的,是找到两个分割点i和j,把两个数组都分为两部分,使A的左部分+B的左部分的和 与 A的右部分+B的右部分的和 相等,而且A/B左部分最大值 < A/B右部分最小值。这样的分割点即是中位数所在的位置。
要确保左右两部分长度相等,即i+j = m+n-i-j,或i+j = m+n-i-j+1(如果是m+n是奇数,不妨设左边比右边多1,因为在后面,j的设定会保证这一点)。
所以,我们可以让 j = (m+n+1)/2 - i,为了让 j 不为负数,所以当 i 最大,即i=m时,j要依然为正,所以令 n>=m,即i遍历短的那个数组。
这样第一点关于左右部分长度的要求就满足了。
之后,对于每次分割,可能遇到以下几种情况:
(1)i < m && j > 0 && B[j - 1] > A[i]
即B的左部分比A的右部分大,即 i 太小而 j 太大,所以此时应增加 i。
(2)i > 0 && j < n && A[i - 1] > B[j]
即A的左部分比B的右部分大,即 i 太大而 j 太小,所以此时应减少 i。
(3)找到完美的分割点
此时有可能 i = m/i = 0,即用于计算中位数的两个数(也可能是一个)仅来自A数组或仅来自B数组。
如果 i 或 j = 0,那么左边部分的最大值为 B[j-1] 或 A[i-1],否则左边部分最大值为max(A[i-1],B[j-1])。
如果 i = m或 j = n,那么右边部分最小值为 B[j] 或 A[i],否则右边部分最小值为min(A[i],B[j])。
如果m+n是偶数,那么中位数=(左边最大值+右边最小值)/2。
否则若m+n是奇数,因为在开始我们默认左边比右边多,所以中位数=左边最大值。
ps:因为复杂度要求,所以增加/减少i的值,都使用二分法。
代码:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(), n = nums2.size(); vector<int> first, second;//first指向短的,second指向长的 if (m > n) { second = nums1; first = nums2; swap(m, n); } else { first = nums1; second = nums2; } int left = 0, right = m; int i, j, _min, _max; while (left <= right) { i = left + (right - left) / 2; j = (m + n + 1) / 2 - i; if (i < m && j > 0 && second[j - 1] >first[i]) { left = i + 1; continue; } else if (i > 0 && j < n && first[i - 1] > second[j]) { right = i - 1; continue; } else { //ok if (i == 0) _min = second[j - 1]; else if (j == 0) _min = first[i - 1]; else _min = max(first[i - 1], second[j - 1]); if (i == m) _max = second[j]; else if (j == n) _max = first[i]; else _max = min(first[i], second[j]); if ((m + n) % 2 == 0) return (double)(_max + _min) / 2; else return (double)_min; } } }结果: