1

题目描述

There are two sorted arrays A and B 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)).

难度:分析繁杂,实现时边界容易弄错

分析

首先,这道题可以归类为“已知一个数组,找到其从小到大排在第K位的元素”。

已经限定了时间复杂度是O(log (m+n)),否则的话,用两个下标i和j分别指向这两个数组,如果A[i] < B[j],则i++,否则j++,直到找到第K大的元素为止,时间复杂度O(m+n)。如果到达到题目所说的复杂度,则必须用二分查找了,知易行难啊。

对于这两个数组,设我们的函数是find(A, B, K),

首先,分别取A[K/2-1] 和B[K - (K)/2 -1]比较(记K-K/2为K'),分如下三种情况:

  1. A[K/2-1] < B[K'-1], 则A[0...(K)/2-1]的所有值都可以忽略了,因为:

    • 假设不能忽略,即A∪B[K-1]就在A[0...K/2-1]里面,取最大值A[K/2-1]为A∪B[K-1]
      由此则B中必定有K'个元素小于A[K/2-1],而又因为A[K/2-1] < B[K'-1],故假设不成立。
  2. A[K/2-1] > B[K'-1],同理B[0...K'-1]的值均可忽略了。
  3. A[K/2-1] = B[K'-1],这就是要找的值了,终止。
  4. 假设发生了情况1(情况2也类似),则我们可以知道:

    • A∪B[K-1]一定在A(K/2-1...len(A))或B中了,因为步骤1已经去掉了的(K-1)/2个元素(注:它们不是最小元素的,但的确小于A∪B[K-1]),于是现在应该是寻找下标大小是第K'的元素了。
    • A = A[(K/2)..len(A)), B = B, K = K - K/2
    • 递归到第一步,当其中一个数组长度为0,则另一个取下标K-1即可;另一种情况是,当K为1时,取min(A[0], B[0])

最终代码:

public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        if (A.length == 0 && B.length == 0) return 0;

        int len = A.length + B.length;
        if (len % 2 == 1) {
            return find(A, B, (len + 1) /2);
        } else {
            double sum = find(A, B, len / 2) +
                         find(A, B, (len + 2)/2);
            return sum / 2;
        }
    }

    double find(int[] A, int[] B, int k) {
        if (A.length == 0) return B[k - 1];
        if (B.length == 0) return A[k - 1];
        if (k == 1) return Math.min(A[0], B[0]);
        //永远假设A的长度小于B,这样就可以仅检查A的长度了
        //因为对于K,它们之间总有一个的长度绰绰有余
        if (A.length > B.length) return find(B, A, k);

        int a = Math.min(A.length,k/2);
        int b = k - a;

        if (A[a-1] < B[b-1]) {
            return find(Arrays.copyOfRange(A, a, A.length), B, k - a);
        } else if (A[a-1] > B[b-1]) {
            return find(A, Arrays.copyOfRange(B, b, B.length), k - b);
        } else {
            return A[a-1];
        }
    }
}

如果对空间复杂有要求的话,可以不用Arrays.copyOfRange的,但是这样就要传入额外的参数指示当前起始点和终止点了,程序会毫不意外的更难看。

吐嘈下,数组下标从0开始真是件反人类的事情。

  • 不能通过减下标得到差值,类似x - 0 = x迟早被坑出死循环
  • 正常思维和下标需要转换,稍有不慎程序就跑挂了

ssnau
1.5k 声望98 粉丝

负能量职业打码师


引用和评论

0 条评论