首页 > 编程语言 >算法 -- 寻找两个正序数组的中位数(二分查找)

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

时间:2023-03-15 16:44:06浏览次数:41  
标签:正序 数字 -- 中位数 int length 数组 nums1 nums2

原题:
给定两个大小分别为 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

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

解答:

  • 如果不考虑时间复杂度这个要求的话,直接归并数组,然后求中位数就行了 ----- 以下有两个思路
  1. 创新数组,双指针指向两个数组,哪个小放哪个进新数组,最后奇数return 新数组res[(length-1)/2],偶数return (res[(length-1)/2]+res[length/2])/2.0
    小提升 : 可以只循环(m+n)/2次,减少一丢丢时间复杂度
  2. 不用创新数组,毕竟最后只需要返回中位数就行了,我们创两个变量,一个left,一个right,存储最终计算所需的两个数据,每次遍历时将上一步right的值赋给left,后面思路同第一个方法,只是把上面存储到新数组,换成改变right变量,最后两个数据相加再减半就好,如果是奇数,left与right值相等
  • 重点来咯,如果按照上面两个解法,时间复杂度为O((m+n)/2),明显不符合题意的O(log(m+n)),若想达到这种复杂度,无疑要使用二分查找

假设我们要找第 7 小的数字。

要找第7小的数字,由于两个数组都由从小到大排序,所以我们只需要递归找出两个数组中各自第k/2小的数字,再相互比较,数字小的则将其前面的数字(包括自己)删去,修改起始位置为当前数字+1,k改为k-删去数字数量

橙色的部分表示已经去掉的数字。

按照上面方法,排除了下排数组中的前三个数字[1,2,3],k改为了4,即继续递归找各数组中第k/2 = 2的数字,3比5小,所以删去上排数组中的[1,3]

同上

通过操作,k值来到了1,只需比较两排数组起始位置的数字即可,返回小的

所以第 7 小的数字是 4。

本题重点(边界,特殊值判断)

我们每次都是取 k/2 的数进行比较,有时候可能会遇到数组长度小于 k/2的时候。

由于k/2 = 3大于了上排数组的总长度2,所以在判断数字前要先判断长度,若存在上图情况,将尾指针指向末尾就好

上图情况为某一排数组已经被删完了,即len1 = 0,我们该怎么办,非常好办,剩下k为多少,直接用另一个数组不就好了吗,记得加完k后要减1噢

上面图片 作者:windliang 链接:https://leetcode.cn/problems/median-of-two-sorted-arrays/solutions/8999/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

下面是我自己看完半抄半打的代码

    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length,n = nums2.length;
        int left = (m+n+1)/2;
        int right = (m+n+2)/2;
        return (getK(nums1,0,m-1,nums2,0,n-1,left)+getK(nums1,0,m-1,nums2,0,n-1,right))/2.0;
    }
    private int getK(int[] nums1,int start1,int end1,int[] nums2,int start2,int end2,int k){
            int len1 = end1-start1+1;
            int len2 = end2-start2+1;
            if(len1>len2)return getK(nums2,start2,end2,nums1,start1,end1,k);
            if(len1 == 0)return nums2[start2+k-1];
            if(k==1)return Math.min(nums1[start1],nums2[start2]);
            int i = start1+ Math.min(len1,k/2)-1;
            int j = start2+ Math.min(len2,k/2)-1;
            if(nums1[i]<nums2[j]){
                return getK(nums1,i+1,end1,nums2,start2,end2,k-(i-start1+1));
            }else{
                return getK(nums1,start1,end1,nums2,j+1,end2,k-(j-start2+1));
            }
        }
}```

标签:正序,数字,--,中位数,int,length,数组,nums1,nums2
From: https://www.cnblogs.com/haipali/p/17218955.html

相关文章