LeetCode Median of Two Sorted Arrays

问题网址:https://leetcode.com/problems/median-of-two-sorted-arrays/description/

问题描述:
给定两个有序数组nums1和nums2大小分别为m和n。
找到两个有序数组的中位数。 整体运行时间复杂度应为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

一个简单想法:
学过归并排序的同学显然知道这是一个归并的过程

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    vector<int> a;
    int i = 0, j = 0;
    while (i < nums1.size() && j < nums2.size()) {
        if (nums1[i] <= nums2[j])
            a.push_back(nums1[i++]);
        else
            a.push_back(nums2[j++]);
    }
    while (i < nums1.size())
        a.push_back(nums1[i++]);
    while (j < nums2.size())
        a.push_back(nums2[j++]);
    if (a.size() % 2)
        return a[a.size() / 2];
    else
        return (a[a.size() / 2 - 1] + a[a.size() / 2]) / 2.0;
}

时间复杂度:O(m + n)

改进的想法:
为了解决这个问题,我们需要了解“中位数的应用”。 统计学中,中位数用于:
将集合划分为两个相等长度的子集,一个子集总是大于另一子集。
如果我们了解中位数的使用,我们非常接近答案。
首先让我们将A随机分为两部分:

          left_A             |        right_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 为空.

以相同的方式将B在随机分成两部分:

          left_B             |        right_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:

          left_part          |        right_part
    A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]
    B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

如果我们能确保:

1. len(left_part)=len(right_part)
2. max(left_part)≤min(right_part)

那么我们将{A,B}中的所有元素分成两个等长的部分,一部分总是大于另一部分。 然后
median = (max(left_part) + min(right_part)) / 2
为了确保这两个条件,我们只需要确保:

i + j = m − i + n − j (or: m - i + n - j + 1)
如果 n ≥ m, 令 i = 0∼m, j = (m+n+1)/2i
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    if (nums1.size() > nums2.size())
        swap(nums1, nums2);
    int m = nums1.size();
    int n = nums2.size();
    int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
    while (iMin <= iMax) {
        int i = (iMin + iMax) / 2;
        int j = halfLen - i;
        if (i < iMax && nums2[j-1] > nums1[i])
            iMin++;
        else if (i > iMin && nums1[i-1] > nums2[j])
            iMax--;
        else {
            int maxLeft = 0;
            if (i == 0)
                maxLeft = nums2[j-1];
            else if (j == 0)
                maxLeft = nums1[i-1];
            else
                maxLeft = max(nums1[i-1], nums2[j-1]);
            if ((m+n) % 2 == 1)
                return maxLeft;

            int minRight = 0;
            if (i == m)
                minRight = nums2[j];
            else if (j == n)
                minRight = nums1[i];
            else
                minRight = min(nums2[j], nums1[i]);

            return (maxLeft + minRight) / 2.0;
        }
    }
    return 0.0;
}

时间复杂度:O(log(m + n))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值