Leedcode 每日一题 —— 寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

 

昨天忙着调区块链的coursework忘了……今天补上。

这题有点难……最初的想法当然是最简单的,将两个数组合并,排序然后求中位数,但是时间复杂度就是O(m+n),题目要求O(log(m+n)),想到了要用二分法来做,但是没想好怎么实现,学习了网上大神们的思路(转载):

其实可以把寻找中位数,转变为寻找数组第k小的数。

a数组长度为n,b数组长度为m;
首先,找a和b两个有序数组中第K小,就是在a中找某个位置i,在b中找某个位置j,其满足条件为:
1、i+j=k
2、a[i-1]<=b[j]&&b[j-1]<=a[i]
这样第K小即为:max(a[i-1],b[j-1]);
其次,我们就可以在a数组中二分查找位置i,相应b中位置j=k-i,但是要注意b中j的位置不能越过b的边界即:0<=j<=m,
这样可以得到在a数组中二分查找的范围:0<=i<=n且k-m<=i<=k即max(0,k-m)<=i<=min(k,n);
我们可以在这个范围内用二分模板查找i的位置。
最后,二分找到i即代码中的le后,注意边界判断如果位置i和j前面都有元素,第k小=max(a[i-1],b[j-1]);如果i=0,
第k小=b[j-1];如果j=0;第k小=a[i-1];
两个有序数组的中位数即为:1、两个数组长度(m+n)为奇数,求第(m+n)/2+1小元素;2、两个数组长度(m+n)为偶数,求
第(m+n)/2小、第(m+n)/2+1小,两者平均值。

提交代码:

class Solution {
public:
    int findKthIndex(vector<int>& nums1, vector<int>&nums2, int k){
        assert(1<=k && k<= nums1.size() + nums2.size());
        int left = max(0,int(k-nums2.size())), right = min(int(nums1.size()),k);
        while (left < right){
            int p = left+(right-left)/2;
            if (nums2[k-p-1] > nums1[p]){
                left = p + 1;
            }
            else{
                right = p;
            }
        }
        int n1=left == 0 ? INT_MIN : nums1[left - 1];
        int n2=left == k ? INT_MIN: nums2[k-left-1];
        return max(n1,n2);  
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int flag = (nums1.size() + nums2.size()) % 2;
        int k = (nums1.size() + nums2.size()) / 2;
        if (!flag){
            return (findKthIndex(nums1,nums2,k) + findKthIndex(nums1,nums2,k+1)) / 2.0;
        }
        else
            return findKthIndex(nums1,nums2,k+1);
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值