LeetCode - 4. Median of Two Sorted Arrays

4. Median of Two Sorted Arrays

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)).
You may assume nums1 and nums2 cannot be both empty.
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:
  这道题,超级超级超级经典。
  其实就是找出两个有序数组的中位数。(题目说有序但是没有说是升序,也没有说是同序,但是默认两个都是升序了)。

方法一(merge):

  这道题一看就很想用merge直接做,试了一下居然没超时。
  计算中位数时,不需要判断数组长度的奇偶性,直接用 第 (len + 1) / 2 位 + 第 (len + 2) / 2 位的值,再除以 2.0 即可(因为奇数加 1 除以 2 和加 2 除以 2,结果一样)。但是由于是 0 为第一位,所以两个位置都需要减一。
  但是题目要求时间复杂度是 O(log (m + n)),而merge是把两个有序数组合并到一个新的里边,没有看底层实现,但是应该是 O(m + n) 的时间复杂度,所以肯定不行,肯定要用二分法,达到要求的时间复杂度。

double findMedianSortedArrays(vector<int>& n1, vector<int>& n2)
{
    const int len1 = n1.size(), len2 = n2.size();
    if (len1 == 0)  return (n2[(len2 + 1) / 2 - 1] + n2[(len2 + 2) / 2 - 1]) / 2.0;
    if (len2 == 0)  return (n1[(len1 + 1) / 2 - 1] + n1[(len1 + 2) / 2 - 1]) / 2.0;
    const int u_len = len1 + len2;
    vector<int> u(u_len, 0);
    // "merge" (default) needs n1 and n2 to be both sorted in ascending order
    merge(begin(n1), end(n1), begin(n2), end(n2), begin(u));
    return (u[(u_len + 1) / 2 - 1] + u[(u_len + 2) / 2 - 1]) / 2.0;
}

方法二(双指针):

  我的第二个想法是用两个指针从前向后走,加起来走一半,就到了中位数的位置了,实现起来还是有边界问题再捣乱,虽然速度是方法一的一倍(因为只需要走一半,不需要全遍历),但是时间复杂度还是 O(m + n) ,所以只是一次尝试,方法一可以AC,下面的代码也理所当然的AC。

double find_mid_two_elements(const vector<int>& n1, const vector<int>& n2, const int& k)
{
	const auto len1 = n1.size(), len2 = n2.size();
	auto i1 = 0, i2 = 0, remain = k, res = 0;
	while (remain != 0)
	{
		if (i1 == n1.size()) return n2[i2 + remain];
		if (i2 == n2.size()) return n1[i1 + remain];
		if (n1[i1] > n2[i2]) ++i2;
		else                 ++i1;
		--remain;
	}
	if (i1 == len1)	     res = n2[i2];
	else if (i2 == len2) res = n1[i1];
	else                 res = min(n1[i1], n2[i2]);
	return res;
}

double findMedianSortedArrays(vector<int>& n1, vector<int>& n2)
{
	const int len1 = n1.size(), len2 = n2.size(), total_len = len1 + len2;
	// e.g. len = 4  --> (n[1] + n[2]) / 2.0, left = 1, right = 2
	// e.g. len = 7  --> (n[3] + n[3]) / 2.0, left = 3, right = 3
	const int left = (total_len + 1) / 2 - 1, right = (total_len + 2) / 2 - 1;
	return (find_mid_two_elements(n1, n2, left) + find_mid_two_elements(n1, n2, right)) / 2.0;
}

方法三(二分法):

  二分法是这道题的推荐解法,但却是挺难写。
  https://blog.csdn.net/yutianzuijin/article/details/11499917/ 这篇文章讲得不错。先记录一下。

double findkth(vector<int>::iterator a,int m, vector<int>::iterator b,int n, int k)
{
    if(m > n)  return findkth(b, n, a, m, k);
    if(m == 0) return b[k - 1];
    if(k == 1) return min(*a, *b);
    const int pa = min(k / 2, m), pb = k - pa;
    if(*(a + pa - 1) < *(b + pb -1))     return findkth(a + pa, m - pa, b, n, k - pa);
    else if(*(a + pa -1) > *(b + pb -1)) return findkth(a, m, b + pb, n - pb, k - pb);
    else                                 return *(a + pa - 1);
}

double findMedianSortedArrays(vector<int>& n1, vector<int>& n2)
{
    const int len1 = n1.size(), len2 = n2.size(), len = len1 + len2;
    if(len & 0x1)
        return findkth(n1.begin(), len1, n2.begin(), len2, len / 2 + 1);
    else
        return (findkth(n1.begin(), len1, n2.begin(), len2, len / 2) 
              + findkth(n1.begin(), len1, n2.begin(), len2, len / 2 + 1))/2;
}

猜你喜欢

转载自blog.csdn.net/Bob__yuan/article/details/87930170