0004. Median of Two Sorted Arrays (H)

Median of Two Sorted Arrays (H)

题目

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log(m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

题意

给定两个升序数组,要求找到由这两个数组组成的数集合的中位数。时间复杂度要求为\(O(log(m+n))\)

思路

常规方法合并后取中位数,复杂度为\(O(m+n)\)。(在合并中排到指定个数时即可停止并返回输出)

复杂度为\(O(log(m+n))\)的方法:结合二分和递归,将问题转化为求两数组组成的集合中第k小的数。每次都比较数组A和B中第k/2小的数A[k/2-1]和B[k/2-1],这里会有以下三种情况:

(记两数组合并后的升序数组为C)

  • A[k/2-1] < B[k/2-1],说明A[0]-A[k/2-1]这k/2个数均小于B[k/2-1],而B[k/2-1]前有k/2-1个数也小于它,那么即使A[k/2-1]取最大,也只能在C中排到第k-1位,不可能是第k小,所以将A[0]-A[k/2-1]这k/2个数全部删去,问题转化为在剩余数组成的集合中求第k-p小的数(用p表示是因为不一定每次都能删去k/2个数,A的长度可能小于k/2,这时会把整个数组删去)。
  • A[k/2-1] > B[k/2-1],与上面的情况相似,这时删去B中的k/2个数,在剩余数组成的集合中求第k-q小的数。
  • A[k/2-1] = B[k/2-1],这时A中有k/2-1个数比A[k/2-1]小,B中也有k/2-1个数比B[k/2-1]小,共有k-2个数比这两个值小,那么在C中A[k/2-1]和B[k/2-1]正好是第k-1和k小的数(并列),即所求的中位数就是A[k/2-1] (或B[k/2-1])。

处理完递归,来考虑边界条件,共有三种情况:

  • 当一个数组中所有数都被排除后,只要在另一个数组中找到对应的第k小数即可。
  • 当k=1时,只要返回两个数组第一个元素中最小的那个。
  • A[k/2-1] = B[k/2-1],已包含在递归处理中。

代码中为了方便处理,总是保持A为长度较小的数组。


代码实现

Java

class Solution {
    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int total = nums1.length + nums2.length;
        // 将奇偶两种情况统一处理
        int a = findkth(nums1, 0, nums1.length - 1, nums2, 0, nums2.length - 1, (total + 1) / 2);
        int b = findkth(nums1, 0, nums1.length - 1, nums2, 0, nums2.length - 1, (total + 2) / 2);
        return 1.0 * (a + b) / 2;
    }
    
    public static int findkth(int[] A, int as, int ae, int[] B, int bs, int be, int k) {
        int alen = ae - as + 1;
        int blen = be - bs + 1;
        // 边界条件处理
        if (alen > blen) {
            return findkth(B, bs, be, A, as, ae, k);
        } else if (alen == 0) {
            return B[k - 1];
        } else if (k == 1) {
            return Math.min(A[as], B[bs]);
        }
        // 递归处理
        int p = Math.min(alen, k / 2);
        int q = k - p;
        if (A[as + p - 1] < B[bs + q - 1]) {
            return findkth(A, as + p, ae, B, bs, be, k - p);
        } else if (A[as + p - 1] > B[bs + q - 1]) {
            return findkth(A, as, ae, B, bs + q, be, k - q);
        } else {
            return A[as + p - 1];
        }
    }
}

JavaScript

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function (nums1, nums2) {
  let len = nums1.length + nums2.length
  let mid1 = findK(nums1, 0, nums1.length - 1, nums2, 0, nums2.length - 1, Math.floor((len + 1) / 2))
  let mid2 = findK(nums1, 0, nums1.length - 1, nums2, 0, nums2.length - 1, Math.floor((len + 2) / 2))
  return (mid1 + mid2) / 2
}

let findK = function (nums1, l1, r1, nums2, l2, r2, k) {
  if (r1 - l1 > r2 - l2) {
    return findK(nums2, l2, r2, nums1, l1, r1, k)
  }
  if (l1 > r1) {
    return nums2[k - 1]
  }
  if (k === 1) {
    return Math.min(nums1[l1], nums2[l2])
  }

  let p = Math.min(r1 - l1 + 1, Math.floor(k / 2))
  let q = k - p

  if (nums1[l1 + p - 1] < nums2[l2 + q - 1]) {
    return findK(nums1, l1 + p, r1, nums2, l2, r2, k - p)
  } else if (nums1[l1 + p - 1] > nums2[l2 + q - 1]) {
    return findK(nums1, l1, r1, nums2, l2 + q, r2, k - q)
  } else {
    return nums1[l1 + p - 1]
  }
}
posted @ 2020-06-15 13:10  墨云黑  阅读(72)  评论(0编辑  收藏  举报