題目:
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)).
解題思路:
這道題,很容易想到的是先排序再直接定位中間那個數即可,m+n為偶數的話,應為中間兩數之和除2,但時間複雜度不符合題目要求,還一種方法就是利用歸併思想,因為兩陣列為排序陣列,對兩陣列進行歸併,當已歸併個數為(m+n)/2時,即求得中間數,不用繼續歸併了,不過這種方式時間複雜度也不符合要求。那有沒其他更快的方法呢。
這裡要說的就是利用二分查詢的方式,當要在排序陣列中查詢某個元素時,我們就應該朝二分法查詢思考。二分法正是利用已排序陣列這一特性快速查詢。該方法的核心是將原問題轉變成一個尋找第k小數的問題(假設兩個原序列升序排列),這樣中位數實際上是第(m+n)/2小的數。所以只要解決了第k小數的問題,原問題也得以解決。首先假設陣列A和B的元素個數都大於k/2,我們比較A[k/2-1]和B[k/2-1]兩個元素,這兩個元素分別表示A的第k/2小的元素和B的第k/2小的元素。這兩個元素比較共有三種情況:>、<和=。如果A[k/2-1]<B[k/2-1],這表示A[0]到A[k/2-1]的元素都在A和B合併之後的前k小的元素中。換句話說,A[k/2-1]不可能大於兩陣列合並之後的第k小值,所以我們可以將其拋棄。
實現程式碼:
#include <iostream> using namespace std; /** 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)). */ class Solution { public: double findMedianSortedArrays(int A[], int m, int B[], int n) { int k = (m + n) / 2; if((m + n) & 0x1)//奇數 return findKthNumber(A, m, B, n, k + 1); return (findKthNumber(A, m, B, n, k) + findKthNumber(A, m, B, n, k+1)) / 2; } double findKthNumber(int A[], int m, int B[], int n, int k) { if(m > n) return findKthNumber(B, n, A, m, k);//這裡始終假設m<n if(m == 0) return B[k-1]; if(n == 0) return A[k-1]; if(k == 1) return A[0] < B[0] ? A[0] : B[0]; int ak = min(k / 2, m); int bk = k - ak; if(A[ak-1] < B[bk-1]) return findKthNumber(A+ak, m-ak, B, n, k-ak); else return findKthNumber(A, m, B+bk, n-bk, k-bk); } }; int main(void) { int A[] = {1,5,7,9,14,15}; int B[] = {3,6,10,13,18,20}; Solution s; double res = s.findMedianSortedArrays(A, 6, B, 6); cout<<res<<endl; return 0; }