【leetCode】4,找出两个有序数组的中位数

方法一、首先直观能想到的是合并两个有序数组,然后找出中间位置的数字,合并两个有序数组有专门的一道题,不难。

方法二、接着我们可能会想到,求中位数,只需要找到第K(k为中位数位置)个元素就可以了,没必要合并整个数组。从第一个元素开始,分别对两个逐一遍历,找到第K大的元素,也不难。

前两种方法都是O(N)级别的时间复杂度。那么O(logN)级别的怎么计算呢?Log级别只能折半查找。于是就有了重点的方法三。

方法三、每次取两个数组各自的第k/2个元素进行比较,扔掉小的那部分,再进行查找。那么为什么不是左右分别找K呢,因为可能会错过。但是k/2为什么一定不会错过呢,因为较大的那个数组目前也才遍历到第k/2个,如果较小那个数组全部都是在小于的范围内,那也刚好到k位置而已,不会超过。

这个解法当时困住我的有这么几个点:

1)奇偶问题,如何确定K?

2)折半查找时除以2以后取哪边,边界问题一直是比较困扰我的问题,总是不能清晰计算,且不漏掉任何情况。

3)一个数组到头了怎么判断?

后来看了题解里一个特别清晰的方法,加上自己的理解,解答如下:


public class test {
    public static void main(String[] args) {
        int[] nums1={1,2,3,4};
        int[] nums2={1,2,3,4,5,6,7,8};
        System.out.println(findMedium(nums1,nums2));
    }
    public static double findMedium(int[] nums1,int[] nums2) {
        int m=nums1.length;
        int n=nums2.length;
        int k1=(m+n+1)/2;
        int k2=(m+n+2)/2;
        return (findKthNum(nums1,0,m-1,nums2,0,n-1,k1)+findKthNum(nums1,0,m-1,nums2,0,n-1,k2))*0.5;
    }
    public static int findKthNum(int[] nums1,int left1,int right1, int[] nums2,int left2,int right2,int k) {
        int width1=right1-left1;
        int width2=right2-left2;

        if(width1==0) return nums2[left2+k-1];
        if(width2==0) return nums1[left1+k-1];
        if(k==1) return nums1[left1]>nums2[left2]?nums2[left2]:nums1[left1];

        int i=left1+Math.min(width1,k/2)-1;//防止一步跨出去了
        int j=left2+Math.min(width2,k/2)-1;
        if(nums1[i]<nums2[j]) {
            return findKthNum(nums1,i+1,right1,nums2,left2,right2,k-Math.min(width1,k/2));
        }
        else {
            return findKthNum(nums1,left1,right1,nums2,i+1,right2,k-Math.min(width2,k/2));
        }
    }
}

1,对于奇偶位,统一归并为求两遍值,然后取平均值,巧。

2,对于有一个空了的情况,直接取剩下另一个的第k个元素,大胆直观。

3,至于步长,每次在剩余长度和折半长度之间取最小值,解决了跨越出去的问题。

4,注意第k个元素是nums[left+k-1],而不是nums[left+k],一开始也犯了这个错误。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值