Skip to Content

leetcode: Median of Two Sorted Arrays

Table of Contents

题目

Median of Two Sorted Arrays 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

主要思想

为找到合适的位置划分两个数组:

在nums1和nums2两个数组中分别截取i,j两个长度,将两个数组划分成4部分,使

  • 划分后两个数组的左部分的数量和与右部分数量和相等 i+j == (m+n)/2 (奇数偶数情况都满足此式) &&
  • 左部分的最大值小于右部分的最小值 max(nums1[i-1], nums2[j-1]) < min(nums1[i], nums2[j]) (由于数组有序)

注: i==0时,nums所有元素被分配到右方; i==nums1.length时,nums所有元素被分到左方

则:

  • 当m+n为偶数时,(max(nums1[i-1], nums1[j-1]) + min(nums1[i], nums2[j]))/2对应的位置为中位数的位置
  • 当m+n为奇数时,max(nums1[i-1], nums1[j-1])对应的位置为中位数的位置

具体实现

在nums1中二分查找i,对于每个i可以直接计算 j=(m+n)/2-i,然后判断是否满足条件,不满足条件则继续搜索。

主要的麻烦在于处理几个极端情况,i、j为0和长度为最大时。

leetcode题目的解决方案提到需要让i成为较长的数组,上面的处理没用到。

此时算法复杂度为O(log(m)),将数组调换位置,每次搜索较短的数组,能够将算法复杂度降低到O**(log(min(m,n)))。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (nums1.length == 0)
            return (nums2[(nums2.length - 1) / 2] + nums2[nums2.length / 2]) / 2.0;
        if (nums2.length == 0) // return median of nums1
            return (nums1[(nums1.length - 1) / 2] + nums1[nums1.length / 2]) / 2.0;

        int iMin = 0;
        int iMax = nums1.length;
        int i;  // represent begin of right array of divided position, range in [0, nums1.length]
        // i = 0 means all nums1 will be put in right
        // i = nums1.length means all nums1 will be put in left

        while (iMin <= iMax) {
            i = (iMin + iMax) / 2;

            int j = (nums1.length + nums2.length) / 2 - i;  // range in [0, jNum.length]
            if (j < 0) {
                iMax = i - 1;
                continue;
            } else if (j > nums2.length) {
                iMin = i + 1;
                continue;
            }

            int leftEnd1; // end element of left part in nums1
            int leftEnd2;
            int rightBegin1;
            int rightBegin2;

            //  nums1 may be all put to right(==0) or left(==nums1.length)
            if (i == 0) {
                leftEnd1 = Integer.MIN_VALUE; // leftEnd1 is not existed
                rightBegin1 = nums1[i];
            } else if (i == nums1.length) {
                leftEnd1 = nums1[i - 1];
                rightBegin1 = Integer.MAX_VALUE;
            } else {
                leftEnd1 = nums1[i - 1];
                rightBegin1 = nums1[i];
            }

            //  nums2 may be all put to right(==0) or left(==nums2.length)
            if (j == 0) {
                leftEnd2 = Integer.MIN_VALUE;
                rightBegin2 = nums2[j];
            } else if (j == nums2.length) {
                leftEnd2 = nums2[j - 1];
                rightBegin2 = Integer.MAX_VALUE;
            } else {
                leftEnd2 = nums2[j - 1];
                rightBegin2 = nums2[j];
            }

            int maxLeftEnd = Math.max(leftEnd1, leftEnd2);
            int minRightBegin = Math.min(rightBegin1, rightBegin2);

            if (maxLeftEnd <= minRightBegin) {
                if ((nums1.length + nums2.length) % 2 == 0)
                    return (minRightBegin + maxLeftEnd) / 2.0;
                else
                    return minRightBegin;
            } else {
                if (j == 0)
                    iMax = i - 1;
                else if (i == 0)
                    iMin = i + 1;
                else if (nums1[i - 1] > nums2[j - 1])
                    iMax = i - 1;
                else
                    iMin = i + 1;
            }
        }

        return -999;
    }
}

public class _4MedianOfTwoSortedArrays {

    public static void main(String[] argv) {
        int[] nums1 = {1, 3, 4};
        int[] nums2 = {2, 5, 8, 10};

        Solution solution = new Solution();
        double result = solution.findMedianSortedArrays(nums1, nums2);
        System.out.println(result);
    }
}