其他分享
首页 > 其他分享> > 【JS】4.寻找两个正序数组的中位数

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

作者:互联网

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

提示:

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

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

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;
};

复杂度分析

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

大佬的链接:4. 寻找两个正序数组的中位数 - 寻找两个正序数组的中位数 - 力扣(LeetCode)

用数组自带的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;
};

复杂度分析

解法二:双指针比较

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

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;
};

复杂度分析

解法三:二分查找

观看Leetcode的视频:寻找两个有序数组的中位数 - 寻找两个正序数组的中位数 - 力扣(LeetCode)

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

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;
};

复杂度分析

标签:正序,复杂度,中位数,JS,length,数组,nums1,nums2
来源: https://www.cnblogs.com/PaturNax/p/16439921.html