LeetCode No.4 Median of Two Sorted Arrays

题目:

即在两个有序数组中找(合并在一起)的中位数。

思路:

自己做的时候没有符合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;
			}
		}
	}
结果:

猜你喜欢

转载自blog.csdn.net/qq_39178023/article/details/80195293