leetcode_4. 寻找两个有序数组的中位数

本文介绍了一种在O(log(m+n))时间复杂度内找到两个有序数组中位数的算法,通过二分查找法,每次排除一半的元素,直至找到第k小的元素。

4. 寻找两个有序数组的中位数

给定两个大小为 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

解析:题目要求O(log(m+n))的时间复杂度,这就代表不能使用简单的数组合并排序然后取数字的方法,而log级别的时间复杂度就代表需要使用二分法。获取n个的中位数,可以理解为获取第(n+1)/2个数字和第(n+2)/2个数字,对于奇数这两个数字是同一个数字,而偶数则为两个相邻的数字。那么就将题目的获取中位数转变为获取第k小数字。
那么如何获取两个数组中第k小的数字呢?我们可以使用二分法,每次对两个数组的第k/2个数字进行比较,因为数组是有序的,因此每一次比较后,相对较小的那个数字与其所在数组之前的所有数字均不可能为第k小的数字,于是每一次比较都可以将k减小一半

例如:
a[1,3,5,7,9]
b[2,4,6,8,10]
k = 5
k/2=2
a[2]<b[2]
因此1、3两个数字不是第k小的数字,因此将其排除,情况就变成了
在a[5,7,9]与b[2,4,6,8,10]两个数组中寻找第(k-2)=3小的数字。
之后k分别为3、2、1,情况变为从a[5,7,9]与b[6,8,10]中寻找第1小的数字
那么便可以得到第5小的数字为5
下面是代码:

class Solution {
public:
    //获取中位数,奇数个可以理解为获取第k/2小的数字
    //偶数则为获取第k/2个数字与k/2+1个数字
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        int m = nums2.size();
        //将奇偶统一,奇数a与b相等,偶数则相差1
        int a = (n+m+1)/2;
        int b = (n+m+2)/2;
        return (findKthmin(nums1,nums2,0,0,a)+findKthmin(nums1,nums2,0,0,b))/2;
    }

    double findKthmin(vector<int>& nums1,vector<int>& nums2,int a,int b,int k){
        int n = nums1.size()-a;
        int m = nums2.size()-b;
        //保证nums1个数均比nums2少
        if(n>m) return findKthmin(nums2,nums1,b,a,k);
        //如果nums1全部排除,那么直接从nums2中选择对应数字返回
        if(n==0) return nums2[b+k-1];
        //k为1时,选择较小的一个返回
        if(k==1) return min(nums1[a],nums2[b]);
        //获取待比较数字的下标,注意-1
        //将n与k/2比较,防止数组越界可能
        //注意此处两个待比较数字的排除范围不一定相等,不能当做k/2来处理
        int i = a + min(n,k/2) -1;
        int j = b + min(m,k/2) -1;
        //如果第一数组比第二数组的大,那么代表第二数组比较数字之前的数字均不可能是第k小的数字
        if(nums1[i]>nums2[j]){
            //排除的是第二数组,因此第一数组仍然从本次比较的位置开始,仍然为a
            //下标b所在位置的数字同样在排除范围内,因此下次从j+1开始
            //排除的数字个数由b的位置决定,排除了(j-b)+1个数字
            return findKthmin(nums1,nums2,a,j+1,k-min(m,k/2));
        }
        else{
            //与之相反
            return findKthmin(nums1,nums2,i+1,b,k-min(n,k/2));
        }
    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值