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...

相關文章
相關標籤/搜索