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

解题:

java:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
       int[] arr3=new int[nums1.length+ nums2.length];
        int p1=0,p2=0,p=0;
        while (p1< nums1.length&&p2< nums2.length){
            int i1 = nums1[p1];
            int i2 = nums2[p2];
            if (i1<=i2){
                arr3[p++]=i1;
                p1++;
            }else {
                arr3[p++]=i2;
                p2++;
            }
            if (p>arr3.length/2){
                if (arr3.length%2==0){
                    return ((double) (arr3[arr3.length/2-1]+arr3[arr3.length/2]))/2;
                }else {
                    return arr3[arr3.length/2];
                }
            }
        }
        if (p1!= nums1.length){
            while (p1< nums1.length){
                arr3[p++]= nums1[p1++];
                if (p>arr3.length/2){
                    if (arr3.length%2==0){
                        return ((double) (arr3[arr3.length/2-1]+arr3[arr3.length/2]))/2;
                    }else {
                        return arr3[arr3.length/2];
                    }
                }
            }
        }
        if (p2!= nums2.length){
            while (p2< nums2.length){
                arr3[p++]= nums2[p2++];
                if (p>arr3.length/2){
                    if (arr3.length%2==0){
                        return ((double) (arr3[arr3.length/2-1]+arr3[arr3.length/2]))/2;
                    }else {
                        return arr3[arr3.length/2];
                    }
                }
            }
        }
        if (arr3.length%2==0){
            return ((double) (arr3[arr3.length/2-1]+arr3[arr3.length/2]))/2;
        }else {
            return arr3[arr3.length/2];
        }
    }
}

javascript:

解题思路
题目要求时间复杂度为O(log (m + n)),一般带有log就要想到二分法

求一个有序数组的中位数,有两种情况:

数组长度为奇数,中位数是数组的中间数字: arr[Math.floor((arr.length + 1) / 2) - 1]
数组长度为偶数,中位数是数组的中间两个数字和除以2: (arr[Math.floor((arr.length + 1) / 2) - 1] + arr[Math.floor((arr.length + 2) / 2] - 1) / 2
上面【】中减一的原因是数组下标从0开始

设i = Math.floor((arr.length + 1) / 2),j = Math.floor((arr.length + 2) / 2

可以将找中位数转化成找有序数组第i小和第j小的数字

设p = Math.floor(k / 2)

在两个正序数组中找第k小的数字步骤:

比较arr1[p - 1]和arr2[p - 1],假设前者小
因为两个数组都是正序,所以arr1中下标在[0, p - 1]范围的都不可能是第k小的数,可以排除,arr1剩下下标[p, arr1.length - 1]
步骤2的[0, p - 1]范围都是比第k小的数字还要小的数字,所以只要在剩下两个数组中找到第k - (p - 1 - 0 + 1)小的数字,新一轮的k = k - (p - 1 - 0 + 1)
重复上面的步骤,直到k === 1,这时候比较两个剩下的数组中第一个数字大小,取最小的就是结果
这个过程中还要考虑特殊情况:

其中一个数组的长度小于p:直接取最后一个数字
其中一个数组长度等于0: 从另一个数组中取第k小的数字
arr1[p - 1] === arr2[p - 1]: 随便删去其中一个数组的前p个数(代码中将它放在else中处理)
代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    let len1 = nums1.length;
    let len2 = nums2.length;
    let left = Math.floor((len1 + len2 + 1) / 2);
    let right = Math.floor((len1 + len2 + 2) / 2);
    return (findkth(nums1, 0, len1 - 1, nums2, 0, len2 - 1, left) + findkth(nums1, 0 , len1 - 1, nums2, 0, len2 - 1, right)) / 2;
};

function findkth(arr1, start1, end1, arr2, start2, end2, k) {
    let n = end1 - start1 + 1;
    let m = end2 - start2 + 1;
    if(n > m) return findkth(arr2, start2, end2, arr1, start1, end1, k);
    if(n === 0) return arr2[start2 + k - 1];
    if(k === 1) return Math.min(arr1[start1], arr2[start2]);
    let i = start1 + Math.min(n, Math.floor(k / 2)) - 1;
    let j = start2 + Math.min(m, Math.floor(k / 2)) - 1;
    if(arr1[i] > arr2[j]) {
        return findkth(arr1, start1, end1, arr2, j + 1, end2, k - (j - start2 + 1));
    } else {
        return findkth(arr1, i + 1, end1, arr2, start2, end2, k - (i - start1 + 1));
    }
}


返回
顶部