代码重构:leetcode 4 寻找两个正序数组的中位数

175 阅读1分钟

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

  • 设两个数组长度分别为m,n
  • 对第一个数组先取前i个数,第二个数组取前(m+n+1)/2-i个数字,组成leftpart,其余剩下的组成rightpart
  • 可以得到len(leftpart)>=len(rightpart)且,当m+n为偶数时候相等,奇数时候len(leftpart)=len(rightpart)+1
  • 如果满足,min(rightpart)>=max(leftpart),那么显然此时答案两种可能
    1. m+n为偶数,答案是(min(rightpart)+max(leftpart))/2
    2. m+n为奇数,答案是max(leftpart)

可以通过二分查找获得。过程如下:

  • 设lpi为第一个数组的第i个数字,rpi为第一个数组的第i+1个数字
  • 设lpj为第二个数组的第j个数字,rpj为第二个数组的第i+1个数字

当我们寻求使用二分寻求解空间的时候,设当前区间为(left,right),i=(left+right)/2,j=(m+n+1)/2-i;

此时若lpi<=rpj:

  • i必须向右移动。简单理解就是i小了,解空间在右边。证明如下

    此时易得lpi<=rpi,lpi<=rpj,lpj<=rpj

        1. 若此时lpj<=rpi,此时为答案即可记录。
        2. 此时若lpj>rpi,证明i需要增大,j需要减小,于是就是解空间的i在右边
    

同理可证得lpi>rpj的情况得向左移动。

tips:需要注意对边界的处理,以及编程时候的定义。

 	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (nums1.length > nums2.length) return findMedianSortedArrays(nums2, nums1);
        int m = nums1.length, n = nums2.length;
        int m1 = 0, m2 = 0;
        int left = 0, right = m;
        while (left <= right) {
            int i = (left + right) / 2;
            int j = (m + n + 1) / 2 - i;
            int lpi = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
            int rpi = i == m ? Integer.MAX_VALUE : nums1[i];
            int lpj = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
            int rpj = j == n ? Integer.MAX_VALUE : nums2[j];
            if (lpi <= rpj) {
                m1 = Math.max(lpi, lpj);
                m2 = Math.min(rpi, rpj);
                left = left + 1;
            } else right = right - 1;
        }
        return (m + n) % 2 == 0 ? (m1 + m2) / 2.0 : m1;
    }