首页 > 其他分享 >寻找两个有序数组的中位数(4)

寻找两个有序数组的中位数(4)

时间:2024-02-03 23:27:41浏览次数:28  
标签:数组 int start1 中位数 start2 len1 有序 nums1 nums2

4 Median of Two Sorted Arrays

问题描述:给定两个大小为 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
//思路一:直接合并然后求解,但是不合题意。
//时间复杂度:O(m+n)
//空间复杂度:O(m+n)
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int len = nums1.length + nums2.length;
    int[] nums = new int[len];
    int index = 0;
    int i = 0;
    int j = 0;
    while(i<nums1.length && j< nums2.length){
        if(nums1[i] < nums2[j]){
            nums[index++] = nums1[i++];
        }else{
            nums[index++] = nums2[j++];
        }
    }
    while(i< nums1.length){
        nums[index++] = nums1[i++];
    }
    while(j< nums2.length){
        nums[index++] = nums2[j++];
    }
    if(len % 2 ==1){
        return nums[nums.length/2]*1.0;
    }else{
        return (nums[nums.length/2] + nums[nums.length/2-1])*1.0 / 2;
    }
}
//思路二:
//1、要求时间复杂度 O(log(m+n)),m+n就是两个数组的长度和,又是有序数组,我们很容易想到二分查找
//2、求出的结果是中位数,中位数的特点是其以后的数都比它大,前面的数都比它小。
//3、两个数组都已经是有序数组,
// 因此我们所需要的结果就是num1[start1,end1]中的第i个元素(下标 start1+i-1)和数组num2[start2,end2]中第j个元素(下标 start+j-1),
///在数组num1[start1,end1]中确定i以及在数组中确定num2[start2,end2],此时可以采用二分查找的方法,
// 通过不断缩小查找范围来确实所需要查找的值,也符合题目中所要求的分治算法的思想。
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int len1 = nums1.length;
    int len2 = nums2.length;
    int k1 = (len1+len2+1)/2;
    int k2 = (len1+len2+2)/2;
    //当 (len1+len2)奇数时,此时 k1==k2;
    //当 (len1+len2)偶数时,此时 k1+1 == k2
    double res =
            (findKth(nums1,0,len1-1,nums2,0,len2-1,k1) +
                    findKth(nums1,0,len1-1,nums2,0,len2-1,k2))/2;
    return res;
}

/**
 * 查找 nums1[start1,end1] 和 nums2[start2,end2]合并后的第 k 小元素
 */
private double findKth(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){
        //这里保持 len1 <= len2,方便后面的操作
        return findKth(nums2,start2,end2,nums1,start1,end1,k);
    }else if(len1 == 0){
        //nums1[start1,start2]数组长度为0,则就是在nums2[start2,end2]中第 k 小的元素
        return nums2[start2+k-1];
    }else if(k == 1){
        //合并后的数组的第1个元素,显然是nums1[start1,end1]和nums2[start2,end2]中第一个元素的较小值
        return Math.min(nums1[start1],nums2[start2]);
    }
    //分治
    int i = Math.min(k/2,len1); //在nums1[start1,end1]中第 i 小元素
    int j = k - i; //在nums2[start2,end2]中第 j 小元素
    if(nums1[start1+i-1] > nums2[start2+j-1]){  //此时 nums2[start2,end2]中就要舍弃前面j个元素
        /**
         * 使用反证法证明:
         * 证:当k/2 >= len1 时,而我们要找的k就在nums2[start2,end2]的前 k/2元素中。
         * 我们假设 k 所在的数组下标记为p,那么nums2[start2,end2]中含有的属于后数组前k个元素的元素有(p+1)个。
         * 显然,nums1[start1,end1]中必然含有另外 k-(p+1)个元素。
         * 由此,得到如下不等式:
         * p <= k/2 - 1 (k th 实际所处位置为p,在nums2[start2,end2]的前k/2个元素里。-1是因为现在算的是数组下标,从0开始)
         * ==> p + 1 <= k/2;
         * ==> k - (p+1) >= k - k/2。
         显然,len1 >= k - (p+1) >= k/2 ,这与上面的假设,k/2 >= len1是矛盾的。
         */
        return findKth(nums1,start1,end1,nums2,start2+j,end2,k-j);  //此时就是求第(k-j)小元素
    }else if(nums1[start1+i-1] < nums2[start2+j-1]){ //此时 nums1[start1,end1]中就要舍弃前面i个元素
        return findKth(nums1,start1+i,end1,nums2,start2,end2,k-i);
    }else{
        return nums1[start1+i-1];
    }
}

参考:

标签:数组,int,start1,中位数,start2,len1,有序,nums1,nums2
From: https://www.cnblogs.com/i9code/p/18005383

相关文章

  • 两数之和-输出有序数组
    167TwoSumII-Inputarrayissorted问题描述:给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值index1和index2,其中index1必须小于index2。说明:返回的下标值(index1和index2)不是从零开始的。你可以假设每个输入......
  • 合并两个有序数组
    88.合并两个有序数组问题描述:给定两个有序整数数组nums1和nums2,将nums2合并到nums1中,使得num1成为一个有序数组。说明:初始化nums1和nums2的元素数量分别为m和n。你可以假设nums1有足够的空间(空间大小大于或等于m+n)来保存nums2中的元素。示例:输......
  • synchronized【如何保证原子性、可见性、有序性】【如何实现原子性 原理解析】【什么
    @TOC转自极客时间如何解决可见性问题?同步原理剖析什么是Monitor?什么是锁优化?......
  • volatile源码解析【解决可见性(依据happened-befor)有序性(依据内存屏障)】
    @TOC转自极客时间解决内存可见性问题volatile实现原理-源码分析......
  • 获取数组中元素的所有组合方式
    代码/***获取words成员的所有组合方式*@param{(string|number)[]}words*@return{(string|number)[][]}*/functioncombine(words){constlist=[]words.forEach((word,idx)=>{constrestWords=[...words.slice(0,idx),...words.slice(......
  • 「KDOI-03」构造数组
    「KDOI-03」构造数组题目描述你现在有一个长度为\(n\)的数组\(a\)。一开始,所有\(a_i\)均为\(0\)。给出一个同样长度为\(n\)的目标数组\(b\)。求有多少种方案,使得通过若干次以下操作,可以让\(a\)数组变成\(b\)。选出两个不同的下标\(1\leqi<j\leqn\),并将\(a_i\)......
  • 2024-02-03:用go语言,你有 k 个背包。给你一个下标从 0 开始的整数数组 weights, 其中 we
    2024-02-03:用go语言,你有k个背包。给你一个下标从0开始的整数数组weights,其中weights[i]是第i个珠子的重量。同时给你整数k,请你按照如下规则将所有的珠子放进k个背包。没有背包是空的。如果第i个珠子和第j个珠子在同一个背包里,那么下标在i到j之间的所有珠......
  • 数组的中心位置-od-python
    数组的中心位置时间限制:1s空间限制:256MB限定语言:不限题目描述:给你一个整数数组nums,请计算数组的中心位置。数组中心位置是数组的一个下标,其左侧所有元素相乘的积等于右侧所有元素相乘的积。数组第一个元素的左侧积为1,最后一个元素的右侧积为1如果数组有多个中心位置,应该返回......
  • 力扣 34. 在排序数组中查找元素的第一个和最后一个位置
    Problem: 34.在排序数组中查找元素的第一个和最后一个位置思路找到大于等于target的下标,然后遍历之后的数组,找到最后的下标。classSolution{public:intf(vector<int>&nums,inttarget){intl=0,r=nums.size()-1;intmid=floor(l+(r-l)*1.0/2);......
  • flat 拍平数组 手写flat拍平数组
    //flat拍平一维数组letflaoatArr=[1,3,5,6,3,6,[3,46,465,3]]letres=flat(flaoatArr)console.log(res);letres=flaoatArr.flat()console.log(res);//手写float数组Array.protot......