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

题目

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

算法的时间复杂度应该为 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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

合并数组

  • 解题思路
    不考虑时间复杂度的话,最简单的就是合并数组,找一下数组中间位置的数。
 public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] nums3 = new int[nums1.length+nums2.length];
        int len = nums3.length;
        int end = len/2;
        int idx1=0;
        int idx2=0;
        int idx3=0;
        while (idx3<=end)
        {
            if(idx2>nums2.length-1)
            {
                nums3[idx3]=nums1[idx1];
                idx3++;
                idx1++;
                continue;
            }
            if(idx1>nums1.length-1)
            {
                nums3[idx3]=nums2[idx2];
                idx2++;
                idx3++;
                continue;
            }
            if(nums1[idx1]>=nums2[idx2])
            {
                nums3[idx3]=nums2[idx2];
                idx2++;
            }
            else
            {
                nums3[idx3]=nums1[idx1];
                idx1++;
            }

            idx3++;
        }
        if(len%2==0)
        {
            return (double)(nums3[end]+nums3[end-1])/2;
        }
        return (double)nums3[end];
    }

二分法

  • 解题思路
    由于题目限制时间复杂组,log(m+n),那么就需要考虑使用二分法。
    在两个数组中,我们可以找到这样一条线,分割两个数组,同时满足两个条件
    1. 分割线左侧的数量等于右侧的数量
    2. 分割线左侧的最大数,小于右侧的最小数
public static double findMedianSortedArrays2(int[] nums1, int[] nums2) {
        //为了方便保证,第一个数组小于第二个数组
        if(nums1.length>nums2.length)
        {
            int[] temp = nums1;
            nums1=nums2;
            nums2=temp;
        }
        int len1= nums1.length;
        int len2 = nums2.length;
        //这个满足奇偶两种情况
        int totalLeft = (len1+len2+1)/2;
        //在区间(0,m]找分割线
        //使得nums1[i-1]<=nums2[j] && nums[j-1]<=num[i]
        int left=0;
        int right=len1;
        //需要找到一条恰当的分割线,分割线,分割两个数组,左面的数要小于右面的数(两个数组是有序的)。
        //这个分割线左侧的元素等于totalLeft = (len1+len2+1)/2;
        while(left<right)
        {
            // i 为nums1的index,每次2分递增
            // j 为nums2的index,等于totalLeft-i
            // i 为分割线在数组1右面那个位置
            int i = left+(right-left+1)/2;
            // j 为分割线在数组2右面那个位置
            int j = totalLeft-i;
            // 分割线,左边数值,大于分割线右边的数值
            // nums1[i-1]<=nums2[j]
            if(nums1[i-1]>nums2[j])
            {
                //不符合条件时
                //下一轮搜索区间[left,i-1]
                right=i-1;
            }else
            {
                //下一轮搜索区间[i,right]
                left=i;
            }
        }
        int i =  left+(right-left+1)/2;
        int j = totalLeft-i;
        int nums1LeftMax = i==0?Integer.MIN_VALUE:nums1[i-1];
        int nums1RightMin = i==len1?Integer.MAX_VALUE:nums1[i];
        int nums2LeftMax = j==0?Integer.MIN_VALUE:nums2[j-1];
        int nums2RightMin = j==len2?Integer.MAX_VALUE:nums2[j];
        if((len1+len2)%2==1)
        {
            return (double)Math.max(nums1LeftMax,nums2LeftMax);
        }else
        {
            return (double)(Math.max(nums1LeftMax,nums2LeftMax)+Math.min(nums1RightMin,nums2RightMin))/2;
        }
    }
posted @ 2022-11-06 17:32  花茶冰糖  阅读(18)  评论(0编辑  收藏  举报