两个排序数组的中位数

给出两个有序数组nums1, nums2, 求 nums1 + nums2的中位数, 并且时间复杂度要求0(log(n+m))
思路:
时间复杂度log,并且数组有序, 所以进而可以想到用二分的方法。
由于数组有序。那么假设我们将数组合并排序,那么中位数 应该是[(n+m-1)/2 + (n+m)/2]/2 或者 (n+m)/2
那么也就是说 假设第一个数组 取 k 个数,那么第二个数组 应该取 mid -k
example
nums1 1 3 5 6 8
nums2 2 3 5
如果 mid 应该是merge 后的 第 3 位 与第 4 位 /2( 1 2 3 3 5 5 6 8)
那么假设 前面 mid - 1个数字, 我有k位是从 nums1 中获取的,那么就会有 mid - k - 1位从 nums2 中获取的。那么 mid = [min(nums1[k+1], nusm2[mid-k]) + max(nums1[k], nums2[mid-k-1])]/2; 那么也就是说我要考虑在nums1中切一刀(k+1与k之间),把nums1切两半,那么同样,nums被切割的位置也应运而生(mid-k-1 与 mid-k)之间。
那么其实问题就演变成。怎样切割nums1,使得切割的左半部分无完全小于有右半边(包括nums1 与nums2)
考虑
这里写图片描述
也就是 最终的跳出条件应该是 ai < bj+1 && bj < ai+1
并且最终的答案就是[ max(ai + bj) + min(bj+1, ai+1) ] / 2
如果 ai > bj+1 , 那么就是 nums1 切的太靠后了,要往前一点,可以用二分。 high = mid - 1;
如果 ai+1 < bj 那么就是nums2 切的太靠前了,要往后一点。low = mid+1
那如果nums1 到头了呢,考虑,由于我们在产生最终答案的时候,最左边的数字一定是取得max,最右边的数组一定是取min,那么为了排除边界的干扰,我们可以把它设置成一个取不到的值,INT_MIN INT_MAX
但是这样就要求我们的 nums1 是 短于nums2 的,这样的话可以确保第一次 切割不回导致nums2 切到头,否则int_min int_max就会影响结果。
以上考虑的是n+m偶数的情况,那么n+m是奇数可能稍微复杂一些,那么我们能不能考虑在不影响结果的情况下,把偶数序列演变成偶数数序列呢。
也就是有什么办法可以使得, f(n) /2 = f(n+1)/2 并且f(n) 恒为奇数
这个时候我们就可以联想到 最长回文子串的manacher算法

[1 4 7 9] [# 1 # 4 # 7 # 9 #] len : 4->9
[2 3 5] [# 2 # 3 # 5 #] len: 3->7
而且个位置可以通过/2得到原来元素的位置。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int len1 = nums1.size();
        int len2 = nums2.size();
        if (len1 > len2)
            return findMedianSortedArrays(nums2, nums1);
        int low = 0, high = len1*2;
        int mid1 = 0, mid2 = 0;
        int l1, l2, r1, r2 = 0;
        while(low <= high) {
            mid1 = (low + high) >> 1;
            mid2 = len1 + len2 - mid1;
            l1 = (mid1 == 0) ? INT_MIN : nums1[(mid1-1)/2];
            r1 = (mid1 == 2*len1) ? INT_MAX : nums1[mid1/2];
            l2 = (mid2 == 0)? INT_MIN : nums2[(mid2-1)/2];
            r2 = (mid2 == 2*len2) ? INT_MAX : nums2[mid2/2];
            if(l1 > r2) 
                high = mid1 - 1;
            else if (l2 > r1)
                low = mid1 + 1;
            else 
                break;
        }
        return (double) (max(l1,l2) + min(r1, r2)) / 2;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值