leetcode004 (二分查找)寻找两个正序数组的中位数

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

难度困难3569

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000

示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -10<sup>6</sup> <= nums1[i], nums2[i] <= 10<sup>6</sup>

My solution(归并法)

import java.util.Arrays;
public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] arr=new int[nums1.length+nums2.length];
        for(int i=0;i<nums1.length;i++)
            arr[i]=nums1[i];
        for (int i =0;i<nums2.length;i++)
            arr[i+nums1.length]=nums2[i];
        Arrays.sort(arr);
        return arr.length%2==1?arr[(arr.length-1)/2]:(arr[arr.length/2]+arr[arr.length/2-1])/2.0;
    }
}

执行用时:5 ms, 在所有 Java 提交中击败了14.05%的用户
内存消耗:39.6 MB, 在所有 Java 提交中击败了81.65%的用户

关于Arrays的sort方法,这里有一篇文章详细介绍了它使用的算法https://www.cnblogs.com/baichunyu/p/11935995.html

我的解法肯定达不到题目要求的时间复杂度O(logn),一般出现这样的对数时间复杂度,都是用到了二分查找法:

二分查找

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n=nums1.length+nums2.length;
        if(n%2==1)//和为奇数,返回第n/2+1个数
                return getMid(nums1,nums2,n/2+1);
        if(n%2==0)//和为偶数,返回第n/2个数和第n/2+1个数的和的一半
                return (getMid(nums1,nums2,n/2)+getMid(nums1,nums2,n/2+1))/2.0;
        else
            return 0;
    }
    public double getMid(int[] nums1, int[] nums2,int k){
        //返回第k个数
        int start1=0,start2=0;
        while(true){
            if(start1==nums1.length)
                return nums2[start2+k-1];
            if(start2==nums2.length)
                return nums1[start1+k-1];
            if(k==1)
                return Math.min(nums1[start1],nums2[start2]);
           int index1=Math.min(start1+k/2-1,nums1.length-1);
           int index2=Math.min(start2+k/2-1,nums2.length-1);
             if(nums1[index1]<=nums2[index2])
            {
                k-=index1-start1+1;
                start1=index1+1;
            }
            else
            {
                k-=index2-start2+1;
                start2=index2+1;
            }
        }
    }
}

该代码是leetcode官方二分法解答的简化版,其主要就是定义了一个函数,运用二分法获取两个数组中从小到大第k个元素

其中start1,start2分别代表数组的起始指针,初始值为0,都指向第一个元素;

进入循环后,首先判断起始指针是否已经到数组的最后,如果是,表示其中一个数组已经判断完了,只需返回剩余数组的第k个元素即为结果

如果k=1,这时两个数组都还没有判断完,这时只需返回剩余数组的最小元素(第一个),即两个数组第一个元素的最小值;

主要部分:
首先获取接下来需要判断的index,这个index不能超过数组的最大值,所以需要判断一下,相应的k也就不能直接写成k-=k/2,因为判断完舍去的元素个数不一定为k/2,新的起始指针设为index+1,因为判断完后,连位置为index的元素也一并舍去了,所以需要从下一个元素开始判断

具体的原理可以直接看下面的链接

时间复杂度为O(logn)的算法要先考虑二分法,这种方法复杂的地方就在于奇偶判断这部分,建议画图,举例解决

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容