二分 寻找两个正序数组的中位数

力扣 寻找两个正序数组的中位数 hard

寻找两个正序数组的中位数

题目

在这里插入图片描述

思路

如下图所示,中位数必然满足这样的分割线, 将两个数组分别分为两个部分,最终组成四个部分,分别为 t1_left, t1_right, t2_left, t2_right, 其中t1代表第一个数组, t2代表第二个数组, left 代表分割线左边的部分, right 代表分割线右边的部分。

  • 要解决的问题就是找到这样一个问题 左边的元素个数为(m+n+1)/2, 用 i表示分割线在 t1中的位置, j代表分割线在 t2中的位置。
  • 那么必须满足 t1[i-1]<=t2[j] && t2[j-1] <= t1[i] && i+j=(m+n+1)/2;
  • 由于 i+j=(m+n+1)/2; 所以只要二分查找出第一个数组中 i的位置,自然确定 j的位置,满足 i位置满足条件t1[i-1]<=t2[j] && t2[j-1] <= t1[i]即可。

在这里插入图片描述

m+n是奇数时,只需要找到中间位置的元素,max(t1_left, t2_left)
m+n是偶数时,需要找到中间俩元素,取平均值 (max(t1_left, t2_left) + min(t1_right+t2_right))/2

值得注意的是,由于是分割线,m个元素的数组有m+1个分割位置,即将所有元素分为right部分 或者 所有元素分为left部分,此时需要边界值处理。
即代码中的如下

double t1_left = (i==0 ? -DBL_MAX : t1[i-1]), t1_right = (i==m ? DBL_MAX : t1[i]) , t2_left = (j == 0 ? -DBL_MAX : t2[j-1]), t2_right = (j == n ? DBL_MAX : t2[j]);

代码

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        vector<int> t1 = nums1, t2 = nums2;
        if ( t1.size() > t2.size() ) {
            vector<int> temp = t1;
            t1 = t2; 
            t2 = temp;
        }
        
        int m = t1.size(), n = t2.size();
        int left = 0, right = m, mid = (m+n+1)/2;
        
        // 找到一条分割线 使得 t1[i-1] <= t2[j] && t2[j-1] <= t1[i] 且 i+j = (m+n+1)/2 分割线的左侧为 
        int i = 0, j = 0;
        // 二分查找 
        while (left < right) {
            i = left + (right - left + 1) / 2;
            j = mid - i;
            if (t1[i-1] > t2[j]) {
                right = i-1;
            } else {
                left = i; // 包含了t1[i-1]==t2[j]的情况 所以不能用left=i+1,而使用left=i,可能导致死循环,通过上述求i,即中位数时 +1
            }
        }
        i = left;
        j = mid - left;
        // cout << i << " " << j;
        
        double t1_left = (i==0 ? -DBL_MAX : t1[i-1]), t1_right = (i==m ? DBL_MAX : t1[i]) , t2_left = (j == 0 ? -DBL_MAX : t2[j-1]), t2_right = (j == n ? DBL_MAX : t2[j]);
        // cout << t1_left << " " << t1_right << "     " << t2_left << " " << t2_right;
        if ( (m+n) % 2 == 1) {
            // cout << t1_left << " " << t2_left << " " << DBL_MIN << " " << DBL_MAX;
            return max(t1_left, t2_left);
        } else {
            return ( max(t1_left, t2_left) + min(t1_right, t2_right) )/2.0;
        }
        return 0.0;

    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值