LeetCode 4. 寻找两个有序数组的中位数【二分答案】

难度: 困难

题目描述

给定两个大小为 m 和 n 的有序数组 nums1nums2
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5

思路1 归并

先把两个有序数组合并成一个有序数组,再计算出中位数。

class Solution {
public:
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
        vector<int> ans;
        for (int i = 0, j = 0, size1 = nums1.size(), size2 = nums2.size(); i < size1 || j < size2;) {
            if (i < size1 && j < size2 && nums1[i] < nums2[j] || i < size1 && j == size2)
                ans.push_back(nums1[i++]);
            else if (i < size1 && j < size2 && nums1[i] >= nums2[j] || j < size2 && i == size1)
                ans.push_back(nums2[j++]);
        }

        if (ans.size() % 2)  return ans[ans.size() / 2];
        else return (ans[ans.size() / 2] + ans[ans.size() / 2 - 1]) / 2.0;
    }
};

思路2 二分答案

设这两个数组中较短的是 a a a,较长的是 b b b a a a b b b的大小分别为 m m m n n n,如果能把这些数分成两个大小相等的集合 A A A B B B(不能相等则让 A A A大1),且 A A A中的所有元素都不大于 B B B中的所有元素,那么中位数也就确定了。问题就在于如何找到 A A A B B B集合在 a a a b b b中的界限。设 i i i j j j分别是 a a a b b b数组中属于 B B B集合的最小的数的下标,如果 i i i确定,则 j j j就也随之确定了。对 i i i的位置进行二分是更好的选择,因为 a a a的长度较小,i可能的答案范围是 [ 0 , m + 1 ) [0, m+1) [0,m+1) 0 0 0代表 a a a中元素全部属于 B B B m m m代表 a a a中元素全部属于 A A A

class Solution {
public:
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2) {
        vector<int> &a = nums1.size() < nums2.size() ? nums1 : nums2;
        vector<int> &b = nums1.size() >= nums2.size() ? nums1 : nums2;
        int m = a.size(), n = b.size();

        int l = 0, r = m + 1, i = (l + r) / 2, j = (m + n + 1) / 2 - i;
        if (m != 0) {  // 较小的数组可能为空
            for (; l != r; i = (l + r) / 2, j = (m + n + 1) / 2 - i) {
                if ((i == 0 || a[i - 1] <= b[j]) && (i == m || b[j - 1] <= a[i])) break;
                
                if (i == 0) l = i + 1;  // b[j - 1] > a[i]
                else if (a[i - 1] > b[j]) r = i;
                else l = i + 1; // i != 0 && a[i - 1] <= b[j] && i != m && b[j - 1] > a[i]
            }
        }

        int lMax = INT_MIN, rMin = INT_MAX;
        if (i != 0) lMax = max(lMax, a[i - 1]);
        if (j != 0) lMax = max(lMax, b[j - 1]);
        if ((m + n) % 2) return lMax;
        if (i != m) rMin = min(rMin, a[i]);
        if (j != n) rMin = min(rMin, b[j]);
        return (lMax + rMin) / 2.0;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值