LeetCode 4_Median of Two Sorted Arrays

Median of Two Sorted Arrayshtml

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

eg.
a=[1,2]
b=[3,4]
median=2.5数组

解法二运行结果:60ms, beats 95.99%.net


解法一:归并想法(Merge)

(不符合时间要求)
依次找到min(a[i],b[j]) 直到第N/2个即为中位数
N= m+n
时间复杂度O(N/2)) 空间复杂度O(1)指针

public double merge(int[] a, int[] b) {
    int N = a.length + b.length;
    int count = 0;
    int mid1 = 0;
    int mid2 = 0;
    int i = 0, j = 0;
    for (; count < (N + 1) / 2; count++) {
        if (a[i] < b[j]) {
            mid1 = a[i];
            i++;
        } else {
            mid1 = b[j];
            j++;
        }
        // System.out.print(mid1 + " ");
    }

    if (N % 2 == 0) {
        if (a[i] < b[j]) mid2 = a[i];
        else mid2 = b[j];
        // System.out.println(mid2);
    } else {
        mid2 = mid1;
        // System.out.println();
    }

    return (mid1 + mid2) / 2.0;
}

引:中位数

中位数和奇偶有关。
N为奇数,中位数为第(N+1)/2个数==第(N+2)/2个数
N为偶数,中位数为第(N)/2个数==第(N+1)/2个数第(N+2)/2个数 的平均值
能够看出不管奇偶时,有神奇的对称美的方法。
然并软,当N为奇数时,中位数是相同的,实际这样作在递归时会算两遍,增长运行时间,所以看看感叹一下就好。
(前提是Java对整数的自动向下取整)
median=0.5*(a[(N-1)/2]+a[(N)/2]);code

注意点1:奇偶性
注意点2:第k个数,在数组的下标为k-1htm

扯句题外话,初中时学的时候奇偶的题想着枚举一下就行了,看这道题的时候心里有点崩溃。
这道题解法二的二分法的主要的难点也就在理清各类奇偶性边界条件上了。blog

解法二:二分法(递归)

时间复杂度O(log(m+n))递归

解题思路:

将a数组的中间元素与b数组的“中间元素”相比较,从而删掉较小元素所在数组的前一半和较大元素所在数组的后一半。递归下去。get

思考歧路,反思与总结:

1.题目改成寻找第k小的元素findKthSortedArrays。

(这里k从1开始计算,k和下标的区别很容易混淆)

这个思路的转变很关键。
缘由在于,若是咱们执着于median,那么在删除一半左右元素造成的子问题中,很难保证仍然是寻找median。可能变为寻找median前一个或者后一个。(由于删除的过程当中,两个数组是分开的,那么奇偶的属性会被遗漏,到最后没法知道到底要一个仍是两个)

改为第k小元素的好处就是,咱们能够将删掉的元素考虑进来,在子问题中不断改变k的值。
(例如:原本咱们须要寻找的median是第5个数,删掉前面2个数以后,在子问题中就变为寻找第5-2=3个数)

考虑a、b数组总数的奇偶性问题,就转化为调用findKthSortedArrays的问题了。

2.实现findKthSortedArrays

1)第k小的k值设定

a.当k==1时,第k小即最小

只需比较两个数组的第一项 a[0]和b[0]
实际状况由于是递归 因此为给定参数的起始值 即比较a[alo]和b[blo] 返回最小值

b.当k>=2时,第k小转化为在每一个数列中取前k一半或一半不到的数,具体为k/2个数,取到a[k/2-1]和b[k/2-1]

Q: 为何取到a[k/2-1]和b[k/2-1],而不是k/2? (k-1)/2?

若是k==2 就是须要比较头两个元素,所以比较的数下标为0,删去1个。
(删去的为较小的那部分,包括被比较的自身,其为前k/2小,确定不可能为第k个元素。说是删除,其实只是移动数组的指针。)
(为何要删去自身?能够不删去自身吗?删去的话能够明确这个数已经被比较过了,若不删去,不知道它究竟是待比较留下的仍是还未比较的)
若是k==3,就是须要比较头两个元素,所以比较的数下标为0,删去1个;若是比较头四个元素,比较的数下标为1,删去2个,会把第3个要求的给删掉了。
综上概括而得。

2)返回值设置

1)当k==1时,返回a[0]、b[0]中小的那个
2)a数组为空时,返回b数组第k个元素
3)b数组为空时,返回a数组第k个元素

3)递归

若a[k/2-1]<b[k/2-1],则从a的中间值index的后一个,即a[index_lo+(k/2-1)+1]开始,和数组b一块儿找第k-k/2个数

作法一:

int i = k / 2 - 1;
    int aMid = Integer.MAX_VALUE, bMid = Integer.MAX_VALUE;
    if (alo + i < a.length) aMid = a[alo + i]; //小于a.length 而不是 a.length-1
    if (blo + i < b.length) bMid = b[blo + i];
    if (aMid < bMid) 
        return find(a, alo + i + 1, b, blo, k - i - 1);
    else return find(a, alo, b, blo + i + 1, k - i - 1);

作法二(本身作的,超过期间):

int i = k / 2 - 1;
    if (alo + i > a.length - 1) i = a.length - 1 - alo;
    if (blo + i > b.length - 1) i = b.length - 1 - blo;
    if (a[alo + i] < b[blo + i])
        return find(a, alo + i + 1, b, blo, k - i - 1);
    else return find(a, alo, b, blo + i + 1, k - i - 1);

4)边界问题:寻找第k小,若数组长度<k怎么办?

如第8小,a的长度为2,b的长度为20
k=8;i=3;
作法一:
将b[3]及以前共4个数删去后,a,b继续找第8-4=4小
k'=4;i=1;
比较a[1]和b[1]...

作法二:
i=2-1=1;
比较a的最后一个,a[1]和b[1]
若a<b,继续找第7小,此时a已经删除光,递归后即刻返回;
反之,继续找第7小,以后可能继续找第6小,第5小...可见运气最坏搜寻时间会变成线性。

边界问题vs返回问题
边界:超出边界,a中仍有元素,不能直接跳过
返回:a为空,可直接跳过只看b

代码:

public class Q4_FindMedianSortedArrays {
    public double findMedianSortedArrays(int[] a, int[] b) {
        int N = a.length + b.length;
        int m1 = find(a, 0, b, 0, (N + 1) / 2);
        int m2 = m1;
        if (N % 2 == 0) m2 = find(a, 0, b, 0, (N + 2) / 2);
        return (m1 + m2) / 2.0;
    }

    public int find(int[] a, int alo, int[] b, int blo, int k) {
        if (alo > a.length - 1) return b[blo + k - 1];
        if (blo > b.length - 1) return a[alo + k - 1];
        if (k == 1) return Math.min(a[alo], b[blo]);

        int i = k / 2 - 1;

        int aMid = Integer.MAX_VALUE, bMid = Integer.MAX_VALUE;
        if (alo + i < a.length) aMid = a[alo + i];
        if (blo + i < b.length) bMid = b[blo + i];

        if (aMid < bMid) return find(a, alo + i + 1, b, blo, k - i - 1);
        else return find(a, alo, b, blo + i + 1, k - i - 1);
    }
}

待补充

顺序统计问题(Order Statistics)

参考连接:
http://blog.csdn.net/ai552368...
http://www.cnblogs.com/gangan...

相关文章
相关标签/搜索