Median of Two Sorted Arrays

406 篇文章 0 订阅
406 篇文章 0 订阅

1,题目要求

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

有两个排序的数组nums1和nums2分别为m和n。

找到两个排序数组的中位数。 总运行时间复杂度应为O(log(m + n))

您可以假设nums1和nums2不能都为空。

2,题目思路

对于这道题,要求是找到两个有序数组的中位数。

中位数,顾名思义,就是一个数组中的中间那个数字。如果是一个数组,很好解决,直接根据数组的长度的奇偶关系,判断中位数是中间的数字还是中间两个数字的平均值。

而对于两个数组的情况,如果我们使用普通的遍历的方法,倒也不难,直接遍历即可,类似于双指针法,但是这种方法的时间复杂度为O(m+n),不满足题目的要求。

因此,这就要求我们另辟蹊径。
这里,使用Discussion中的1.5k赞同的讲解:

首先,在统计中,中位数用于将集合分成两个长度相等的子集,一个子集中的值总是要大于另一个子集中的值。

如果我们对于数组A,随机取一个位置i,将其分成两部分 :

left_Aright_A
A[0], A[1], ..., A[i-1]A[i], A[i+1], ..., A[m-1]

由于A有m个元素,因此,一共有m+1中分割方法(i = 0~m)。
易得:

  • len(left_A) = i
  • len(right_A) = m - i

当i = 0时,left_A为空,而当i = m时,right_A为空。

用同样的方法,随机取一个位置j,将数组B分成两个部分。

left_Bright_B
B[0], B[1], ..., B[j-1]B[j], B[j+1], ..., B[n-1]

将left_A和left_B放在一组中,并将right_A和right_B放在另一组中,此时,我们将它们分别命名为:left_part和right_part。

在这里插入图片描述

如果在这里,我们可以确保以下两点:

  • (1)len(left_part) == len(right_part)
  • (2)max(left_part) <= min(right_part)

那么,我们就将{A, B}中的所有元素划分成了两个长度相等的部分,并且一部分的值总是大于另外一部分。
此时,中位数 = max(left_part) = min(right_part))/2

而对于上面的两个条件,我们只需要确保:

  • (1)i + j == m - i + n - j (or: m - i + n - j + 1)
  • (2)B[j-1] <= A[i] and A[i-1] <= B[j]

于是,问题就转化为了在[0, m]中搜索一个i,使得:

  • B[j-1] <= A[i] and A[i-1] <= B[j], ( where j = (m + n + 1)/2 - i )

这里,m<=n,因为我们要保证j为非0的正值,因为0 <= i <= m而且j = (m + n + 1)/2 - i,如果n < m,j有可能为负。

为了降低算法的时间复杂度,我们使用二分搜索,具体步骤如下:
1,设置imin = 0,imax = m,在[imin, imax]内进行搜索
2,设置i = (imin + imax)/2, j = (m+n+1)/2 - i
3,此时,我们有len(left_part)==len(right_part),并且,会出现以下三种情况:

  1. B[j-1] <= A[i] and A[i-1] <= B[j]
    根据上面的阐述,此时我们找到的i就是正确的,停止搜索。
  2. B[j-1] > A[I]
    这意味着A[i]小了,因此我们需要对i进行“调整”,以使得B[j-1] <= A[i]。而调整的方法,就是增加i,增加了i,j也就相对应减少,A[i]增大、B[j-1]减小,B[j-1] <= A[i]说不定就会成立。
    此时,我们将搜索的范围设置到[i+1, imax],于是imin = i+1,返回到第2步。
  3. A[i-1] > B[j]
    这意味着A[i-1]大了,于是我们需要减少i,使得A[i-1]<=B[j]。此时,我们的搜索范围是[imin, i-1],于是imax = i-1,返回到第2步。

当i找到时,我们就有中位数:

  • 当m+n为奇数时:max(A[i-1], B[j-1])
  • 当m+n为偶数时:(max(A[i-1], B[j-1]) + min(A[i], B[j]))/2

然而,如果对于边界情况: i=0,i=m,j=0,j=n,此时A[i-1],B[j-1],A[i],B[j] 可能不存在。
如果A[i-1],B[j-1],A[i],B[j] 其中有的不存在,我们就不必去检查条件了。比如,如果i = 0, 那么A[i-1]一定不存在,我们也就不必检查A[i-1]<=B[j]了。

于是,对于之前的步骤:
我们在[0, m]中搜索i,使得:

(j == 0 or i == m or B[j-1] <= A[i]) and
(i == 0 or j == n or A[i-1] <= B[j])
where j = (m + n + 1)/2 - i

而在搜索的过程中,我们有有以下三种情况:

  1. (j == 0 or i == m or B[j-1] <= A[i]) and (i == 0 or j = n or A[i-1] <= B[j])
    此时i是完美的,停止搜索
  2. j > 0 and i < m and B[j - 1] > A[i]
    此时i过小,需要增加i。
  3. i > 0 and j < n and A[i - 1] > B[j]
    此时i过大,需要减少i。

3,代码实现

static const auto s = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size(), l = 0, r = m;
        if(m > n)
            return findMedianSortedArrays(nums2, nums1);	//这点不是递归!只是为了保证m <= n
        
        while(l <= r){
            int i = (l + r)/2, j = (m+n+1)/2 -i;
            if(i!=0 && nums1[i-1] > nums2[j])
                r = i-1;
            else if(i < m && nums2[j-1] > nums1[i])
                l = i+1;
            else{
                int lmax = !i ? nums2[j - 1] : (!j ? nums1[i - 1] : max(nums1[i - 1], nums2[j - 1]));
                if((m+n)%2)
                    return lmax;
                else{
                    int rmin = i == m ? nums2[j] : (j == n ? nums1[i] : min(nums1[i], nums2[j]));
                    return 0.5 * (lmax + rmin);
                }
            }        
        }
        return 0.0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值