1、問題描述
給定兩個數組A與B,其大小分別為m、n,假定它們都是已按照增序排序的數組,我們用盡可能快的方法去求兩個數組合並后第k大的元素,其中,1\le k\le(m+n)。例如,對於數組A=[1,3,5,7,9],B=[2,4,6,8]。我們記第k大的數為max_{k-th},則k=4時,max_{4-th}=4。這是因為排序之后的數組A+B=[1,2,3,4,5,6,7,8,9],第4大的數是4。我們針對這一個問題進行探討。
2、算法一
第一眼看到這個題的時候,我們能夠很快地想出來最基本的一種解法:對數組A和B進行合並,然后求出其第k大的數,即找到答案。合並的過程,我們可以參考歸並排序的合並子數組的過程,時間復雜度為O(m+n)。下面給出算法:

int findKthMaxNumOfArrays(int *a,int m,int *b,int n,int k) { int *p=a; int *q=b; int i=0; int j=0; int cur=0; while(i<m&&j<n) { if(a[i]<b[j]) { cur++; if(cur==k) return a[i]; i++; } else { cur++; if(cur==k) return b[j]; j++; } } while(i<m) { cur++; if(cur==k) return a[i]; i++; } while(j<n) { cur++; if(cur==k) return b[j]; j++; } }
3、算法二
實際上算法一的時間復雜度已經是線性的了。可是,是否存在更快的算法能夠完成這項任務呢?答案是肯定的,時間復雜度可以縮短到O(log(m+n))時間內。在這種算法中,二分的思想十分重要。我們將數組A分為兩半,前一部分的大小為\left \lfloor \frac{m}{2} \right \rfloor,后一部分為m- \left \lfloor \frac{m}{2} \right \rfloor;數組B同時分為這樣兩部分,第一部分的大小為\left \lfloor \frac{n}{2} \right \rfloor,第二部分的大小為n- \left \lfloor \frac{n}{2} \right \rfloor。如下圖所示:
通過a_{\frac{m}{2}}與b_{\frac{n}{2}},我們將每個數組分為2部分,分別記為A1、A2和B1、B2。假定b_{\frac{n}{2}} \ge a_{\frac{m}{2}},如果不是,我們只需要交換A、B兩個數組即可。接下來,我們看第k大的數落在了哪個區間里面,令t=a_{\frac{m}{2}}+b_{\frac{n}{2}}+1,這個t實際上是包含了A1,a_{\frac{m}{2}},B1。如果k\le t時,則說明max_{k-th}肯定不在B2里面,這是由於:B2中的所有數\ge b_{\frac{n}{2}},而b_{\frac{n}{2}} \ge A1,B1中的所有數與a_{\frac{m}{2}},而這部分數總共有t個,說明b_{\frac{n}{2}}起碼是第t+1個,若max_{k-th}出現在B2中,則說明k\ge t+1,與假設矛盾。我們可以得出該結論。因此,在判斷之后,我們可以剔除數組B的B2部分,然后再在新數組中尋找;另外,如果k\ge t,則說明max_{k-th}肯定不在A1部分,這部分的證明同上一個證明相同,不再贅述。同樣地,在判斷之后,我們可以剔除數組A的A1部分,然后再在新數組中尋找。基於這樣一種思想,我們每次迭代,都刪除了其中一個數組中一半的元素,時間復雜度大約可認為是O(log(m+n))。
在實現的時候,我們需要特別注意邊界條件,詳細的代碼如下:

int findKthMaxNumOfArrays(int *A, int m, int *B, int n, int k) { if(m == 0)return B[k-1]; if(n == 0)return A[k-1]; int i = m>>1, j = n>>1, *p, *q, t; if(A[i] <= B[j])p = A, q = B; else p = B, q = A, swap(i, j), swap(m, n); t = i + j + 1; if(t >= k)return findKthMaxNumOfArrays(p, m, q, j, k); else if(t < k)return findKthMaxNumOfArrays(p+i+1, m-i-1, q, n, k-i-1); }
4、擴展問題
通過算法二,我們很容易地解決一個類似的問題:求兩個已序數組A,B的中位數。所謂的中位數,對於一個有n個元素的已序數組,如果n是奇數,則中位數是第\frac{n+1}{2}個元素的值;如果n是偶數,則它的中位數是第\frac{n}{2}與第\frac{n}{2}+1數的平均值。對於m+n為奇數,則利用算法二求第\frac{n+m+1}{2}個元素的值即可,對於m+n為偶數,利用算法二求第\frac{m+n}{2}個與第\frac{m+n}{2}+1個元素的值,求其平均值即可。
對於這個問題,在LeetCode中有另外一種解法,但是閱讀后發現其需要處理的個別case太多,相比而言沒有本文所介紹的算法簡潔。如果想要了解,給出鏈接:http://leetcode.com/2011/03/median-of-two-sorted-arrays.html。