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

146 阅读1分钟

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

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

解法一:二分算法

解题思路:这题可以用二分算法,首先就是先确认中位数k的位置,如果是基数中位数就是两个数组和除以2向上取整个位数,索引要减一,偶数就是基数加一加基数除以二,确认中位数之后,然后两个数组每次减去二分之一中位数,加入算出nums1的前二分之k的位置为a,nums2的前二分之k为位置b=,如果nums1[a] <= nums2[b]那么k在nums[a]之后,在nums2[b]之前,反之就是在nums[a]之前,nums2[b]之后,代码如下:

var findMedianSortedArrays = function(nums1, nums2) {
    //现获取数组总长度
    let leng = nums1.length + nums2.length;
    //获取中间位置,这里是索引从1开始,第几位,如果是获取数组索引需要减一
    let m = (leng + 1) >> 1;
    //查找第m位数
    let a = findk(nums1,nums2,0,0,m);
    //如果数组是偶数就再取下一位,求和
    if(leng % 2 == 1) return a;
    let b = findk(nums1,nums2,0,0,m + 1);
    return (a + b) / 2;
};

let findk = function(data1,data2,i,j,k){
    //当第一个数组是空时,就返回第二个数组的第k位,因为上面k索引是从1开始,所以需要减一
    if(i == data1.length) return data2[j + k - 1];
    //同上
    if(j == data2.length) return data1[i + k - 1];
    当k等于1,说明两个数组都只剩一,谁小取谁
    if(k == 1) return data1[i] < data2[j] ? data1[i] : data2[j];
    //因为数组会有不够减的情况,所以谁小取谁的个数
    let a = Math.min(parseInt(k/2),data1.length - i);
    //第一个数组取几个剩下的在b里取,因为数组2也会有不够取的情况,所以取小
    let b = Math.min(k - a, data2.length - j);
    //因为会出现数组2不够取,所以需要重置a
    a = k - b;
    //当data1二分之k的位置小于data2二分之k的位置的时候,k在数组data1[k/2]之后和data2[k/2]之前
    if(data1[i + a - 1] <= data2[j + b - 1]){
       //去掉data1[k/2]之前的位置,更新data1的其实位置
        return findk(data1,data2,i + a,j,k - a);
    }
    此时k在data1[k/2]之前和data2[k/2]之前后,需要更新data2的其实位置
    return findk(data1,data2,i,j + b,k - b);
}

解法2:归并算法的合并操作

解题思路:将两个有序数组合并成一个数组,谁小谁入栈,然后求中间位置,代码如下:

var findMedianSortedArrays = function(nums1, nums2) {
    //定义新的数组接收合并后的数组
    let data = [];
    //直到两个数组都出栈了,就结束
    while(nums1.length > 0 || nums2.length > 0){
        //当数组2位空,谁小谁出栈
        if(nums2.length < 1 || nums1[0] <= nums2[0]){
            data.push(nums1.shift())
        } else if(nums1.length < 1 || nums1[0] > nums2[0]){
            data.push(nums2.shift());
        }
    }
    let leng = data.length;
    let m = parseInt(leng/2);
    //判断数组长度是基数还是偶数
    if(leng % 2 == 1){
        return data[m]
    } else {
        return (data[m] + data[m - 1]) / 2;
    }
};