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

给定两个大小分别为 mn 的正序(从小到大)数组 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

提示:

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

解法一:暴力(啰嗦的写法)

就两个数组合并成一个新的有序数组,然后取中间值

var findMedianSortedArrays = function(nums1, nums2) {
    var m=nums1.length,n=nums2.length;
    //要判断有长为0的情况
    if(m===0){
        return n%2===0 ? (nums2[n/2] + nums2[n/2 -1])/2 : nums2[Math.floor(n/2)];
    }
    if(n===0){
        return m%2===0 ? (nums1[m/2] + nums1[m/2 -1])/2 : nums1[Math.floor(m/2)];
    }
    //两个数组根据大小比较来排序合并,数组可以用push或者直接开个固定的空间
    var nums=[],i=0,j=0;
    //两个都可以比的时候
    while(i<m && j<n){
        if(nums1[i]<nums2[j]){
            nums.push(nums1[i]);
            i++;
        }else{
            nums.push(nums2[j]);
            j++;
        }
    }
    //任意一个数组比完了,那么另一个一直加下去
    while(i<m){
        nums.push(nums1[i++]);
    }
    while(j<n){
        nums.push(nums2[j++]);
    }

    //原来合并后的数组有长度这个属性的
    const {length} = nums;
    return length % 2 === 1 ? nums[Math.floor(length/2)] : (nums[length/2] + nums[length/2 -1])/2;
};

复杂度分析

  • 时间复杂度:\(O(max(m, n))\),\(m\)为\(nums1\)的长度,\(n\)为\(nums2\)的长度
  • 空间复杂度:\(O(m + n)\)

解法一:暴力(简洁的写法)

用数组自带的concat函数把两个数组合并到一起,接着使用sort()函数进行排序。另外根据B战的蛋老师的一期视频,在JS的sort()跟我所学的C++或python都不太一样,不能直接用。

var findMedianSortedArrays = function(nums1, nums2) {
    let len = nums1.length + nums2.length;
    let nums = nums1.concat(nums2).sort((a,b) => a-b);
    return len % 2 === 1 ? nums[Math.floor(len/2)] : (nums[len/2] + nums[len/2 -1])/2;
};

复杂度分析

  • 时间复杂度:\(O((m+n)log(m+n))\),简洁带来的坏处就是时间效率下降
  • 空间复杂度 \(O(m+n)\)

解法二:双指针比较

就没必要合并两个数组,本质就是两个指针进行对比。

var findMedianSortedArrays = function(nums1, nums2) {
    let m=nums1.length,n=nums2.length,len=m+n;
    //创建两个指针,指针的作用除了移动到指定的中位数位置
    //还要辅助判断数组的大小才行,所以还要添加两个辅助变量
    //进一步判断返回最终偶数或奇数时对应的中位数的大小
    let point1=0,point2=0;
    let preValue=-1,curValue=-1;
    //最多就变量(m+n/2)次
    for(let i = 0;i<=Math.floor(len/2);i++){
        preValue=curValue;
        //除了正常的比较大小外,还要考虑任意一方没法再比较的情况
        if(point1<m && (point2 >= n || nums1[point1] < nums2[point2])){
            curValue = nums1[point1++];
        }else{
            curValue = nums2[point2++];
        }
    }
    //Math.floor(是向下取数的)
    return len%2===0 ? (preValue + curValue)/2 : curValue;
};

复杂度分析

  • 时间复杂度\(O(m+n)\)
  • 空间复杂度\(O(1)\)

其实就是两个都弄个分段,结合数组有序的性质与在最短长的数组中二分查找出分隔线的方式,总可以找到一个符合要求的中间值。

java n o 中位数 js中位数_Math

var findMedianSortedArrays = function(nums1, nums2) {
    //保证nums1长度小于nums2,因为他们的分隔线位置互相影响
    if(nums1.length > nums2.length){
        [nums1,nums2] = [nums2,nums1];
    }
	//取长度
    let m=nums1.length,n=nums2.length;
	//在0~m区域
    let left=0,right=m;
	//暂存左半段的最大值,右半段的最小值
    let median1=0,median2=0;
    
    while(left<=right){
        //找nums1这里的中位线作为分隔线
        const i = left +Math.floor((right-left)/2);
        //想象两个数组合并成一个新数组的总长度取中位线 - 左半段的分隔线,就是右半段分隔线的初始位置
        const j = Math.floor((m+n+1)/2)-i;
      //判断特殊情况,比如num1的中位线就是在下标0处,那么这分隔线也就缺乏意义了。
        const maxLeft1 = i === 0 ? -Infinity : nums1[i-1];
        const minRight1 = i === m ? Infinity : nums1[i];

        const maxLeft2 = j === 0 ? -Infinity : nums2[j-1];
        const minRight2 = j === n ? Infinity : nums2[j];

        //不停通过二分查找调整分隔线的位置,直到找到对应的数组,然后取中间值
        if(maxLeft1<=minRight2){
            median1=Math.max(maxLeft1,maxLeft2);
            median2=Math.min(minRight1,minRight2);
            left = i+1;
        }else{
            right = i-1;
        }
    }
    return (m+n) % 2 == 0 ? (median1 + median2) /2 : median1;
};

复杂度分析

  • 时间复杂度:\(O(\log\min(m,n)))\),其中 \(m\) 和 \(n\) 分别是数组 \(\textit{nums}_1\) 和 \(\textit{nums}_2\) 的长度。查找的区间是 \([0, m]\) ,而该区间的长度在每次循环之后都会减少为原来的一半。所以,只需要执行 \(\log m\) 次循环。由于每次循环中的操作次数是常数,所以时间复杂度为 \(O(\log m)\)。由于我们可能需要交换 \(\textit{nums}_1\) 和 \(\textit{nums}_2\) 使得 \(m \leq n\),因此时间复杂度是 \(O(\log\min(m,n)))\)。
  • 空间复杂度:\(O(1)\)。