Leetcode 04:寻找两个有序数组的中位数(详解二分法)

题目

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

详解:

题目要求时间复杂度,在此贴上讲解时间复杂度的一个通俗帖子:https://zhuanlan.zhihu.com/p/50479555,OK那么在这道题中显然不是让我们合并两数组去编写(时间复杂度),在网上查阅一番,学习了用二分法解题。
本题中的二分法如下

较小数part较大数part
part1:nums1[0] …nums1[i-1]part3:nums1[i] …nums1[m-1]
part2:nums2[0] …nums2[j-1]part4:nums2[j] …nums2[n-1]

我们的目的是找好分界点i和j的取值,从而使得part1和part2中的所有元素<part3和part4中的所有元素,且要使part1与part2中元素个数为(m+n+1)/2个(why?为了定位中位数)。
因为有序,显然part1中元素<part3中元素,part2中元素<part4中元素
故现在只需将分界点做调整,使nums1[i-1]<nums1[j]且nums1[j-1]<nums1[i]
这个过程中会遇到的问题:
1.奇偶性
如果你明白上文加粗字的部分,那么奇偶性将不是问题。
(1)若nums1和num2组成的大数组内元素个数是奇数,那么显然中位数应该是第(m+n+1)/2个元素,所以从值最小的part1、part2开始看,显然max{nums1[i-1],nums2[j-1]}即为所求。

(2)若大数组内元素个数是偶数,中位数则为第(m+n+1)/2个与第(m+n+1)/2+1个元素的平均值,即max{nums1[i-1],nums2[j-1]}与min{nums1[i],nums2[j] }的平均值。

2.临界点
遇到临界点怎么办?如果你理解上文加粗部分就会知道,取大取小的部分就可以省了,留下的那个就是你要的

下面开始贴代码(C#)

public class Solution {
    public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
        int m=nums1.Length;
        int n=nums2.Length;
        int maxleft=0;
        int minright=0;
        int flag=(m+n)%2;
        if(m>n)
        {
            return FindMedianSortedArrays(nums2, nums1); 
        }
        
        //二分法
        int k=(m+n+1)/2;
        int start=0;
        int end=m;
        
        while(start<=end)
        {
            int i=(start+end)/2;
            int j=k-i;
            if(i>start&&nums1[i-1]>nums2[j])//cut需要向前移
           {
               end=i-1;
           }
           else if(i<m&&nums2[j-1]>nums1[i])//cut需要向后移
           {
               start=i+1;
           }
           else//cut的刚好
           {
               if(i==0){maxleft=nums2[j-1];}
               else if(j==0){maxleft=nums1[i-1];}
               else{maxleft=Math.Max(nums1[i-1],nums2[j-1]);}
               if(flag==1){return maxleft;}
            
               if(i==m){minright=nums2[j];}
               else if(j==n){minright=nums1[i];}
               else{minright=Math.Min(nums1[i],nums2[j]);}
               return (maxleft+minright)/2.0;
           }
        }
        return 0;
    }
    }

结果:

执行用时:172ms 击败94.21%用户
内存消耗:26.7M 击败5.05%用户

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值