leetcode题解-4.寻找两个有序数据的中位数


博客专栏地址:https://blog.csdn.net/feng964497595/category_9848847.html
github地址:https://github.com/mufeng964497595/leetcode


题目描述

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

思路解析

  1. 只是找中位数很简单,但是题目要求算法的时间复杂度为O(log(m+n)),那就不能用常规方法了。一般看到时间复杂度logn的,就先试试二分可不可以。按照题目示例,这两个数组都是升序数组。
  2. 对于两个有序数组nums1和nums2,假设数组长度分别为len1和len2,把两个数组整合起来,如果len1+len2是奇数,那么他们的中位数是第(len1+len2+1)/2个数(从1开始数);如果len1+len2是偶数,那么他们的中位数是位置在(len1+len2+1)/2和(len1+len2+2)/2的这两个数的平均值。那么其实可以把这两种情况整合起来,即中位数是位置在(len1+len2+1)/2和(len1+len2+2)/2的这两个数的平均值。所以问题就变成了求两个有序数组中,排在第K位的数是多少
  3. 前面又说要用二分,由于第K位的数要么在数组1,要么在数组2,那就让两个数组各自找他们的第k/2位的数是多少,由于数组是升序,那么小的那部分就可以直接舍弃了(因为只丢了k/2个数,而目标是第k个,不会把答案丢掉)。如果某个数组的长度小于k/2,那么就取数组的最后一个数就可以。舍弃后目标就从第k位变成了第k-舍弃的长度
  4. 如果舍弃后某个数组空了,那么答案就在剩下的数组上,直接取第k位。
  5. 如果k=1,那么就只需要判断两个数组的第一个数,谁小答案就是谁。
  6. 不断递归处理剩下来的数组,知道找到第K个数就可以了。

以数组{1,3,5,7}和{2,3,4}为例,要找出第(4+3+1)/2=4位和第(4+3+2)/2=4位数。即k=4。
那么两个数组各找第k/2=2个数,得到3和3,两个数相同,舍掉谁都行,就以舍掉数组1为例,此时数组剩下{5,7}和{2,3,4},k = k-2 = 2。
再继续找第k/2=1个数,得到5和2,5>2,所以舍弃数组2,此时数组剩下{5,7}和{3,4},k = k-1=1。
由于k=1了,就只需要判断两个数组的第一个数组的大小,取小的那一个。由于5>3,所以两个数组的第k个数就是3了。所以中位数就是(3+3)/2=3。

示例代码

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int size1 = nums1.size();
        int size2 = nums2.size();
        double res1 = FindKth(nums1, nums2, 0, size1 - 1, 0, size2 - 1, (size1 + size2 + 1) >> 1);
        double res2 = FindKth(nums1, nums2, 0, size1 - 1, 0, size2 - 1, (size1 + size2 + 2) >> 1);
        return (res1 + res2) / 2.0;
    }

private:
    double FindKth(const vector<int>& nums1, const vector<int>& nums2, int left1, int right1
            , int left2, int right2, int k) {
        if (left1 > right1){
            // 数组1是空的,直接可以从数组2得到结果
            return nums2[left2 + k - 1];
        } else if (left2 > right2) {
            // 数组2是空的,直接可以从数组1得到结果
            return nums1[left1 + k - 1];
        }

        if (1 == k) {
            // 找两个数组的第一个进行比较,取小的那个就行
            return std::min(nums1[left1], nums2[left2]);
        }

        int tmp = k >> 1;
        int idx1 = std::min(right1, left1 + tmp - 1);
        int idx2 = std::min(right2, left2 + tmp - 1);
        if (nums1[idx1] < nums2[idx2]) {
            // 舍弃数组1的前半部分
            return FindKth(nums1, nums2, idx1 + 1, right1, left2, right2, k - (idx1 - left1 + 1));
        } else {
            // 舍弃数组2的前半部分
            return FindKth(nums1, nums2, left1, right1, idx2 + 1, right2, k - (idx2 - left2 + 1));
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值