原題爲:算法
There are two sorted arrays nums1 and nums2 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)).數組
好吧,我是普通青年,第一反應就是使用Merge兩個數字的思想,直接找到中位數。可是這個算法的複雜度是O(m+n)。ide
leetcode給這道題打上的標籤是divide and conquer以及binary search。其實我以爲這個標籤有點誤導性。百思不得其解以後看了關於這道題的discussion,看完以後不由感嘆:我數學沒學好。編碼
這道題的解題思路是這樣子的:code
該方法的核心是將原問題轉變成一個尋找第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小值,因此咱們能夠將其拋棄。而後在兩個數組剩下的元素裏尋找第k-(k/2)大的元素(經過遞歸的方式)。leetcode
當A[k/2-1]>B[k/2-1]時存在相似的結論。數學
當A[k/2-1]=B[k/2-1]時,咱們已經找到了第k小的數,也即這個相等的元素,咱們將其記爲m。因爲在A和B中分別有k/2-1個元素小於m,因此m便是第k小的數。(這裏可能有人會有疑問,若是k爲奇數,則m不是中位數。這裏是進行了理想化考慮,在實際代碼中略有不一樣,是先求k/2,而後利用k-k/2得到另外一個數。)it
如何證實以上的規律是數學書裏的內容,這裏不作太多介紹。io
在實際的編碼過程當中,咱們須要考慮以下邊界條件:
1. 若是m或者n爲0,直接返回A[k-1]或者B[k-1];
2. 若是k爲1,那麼返回A[0]或者B[0]當中較小的一個;
3. 若是A[k/2-1] == B[k/2-1],那麼直接返回兩個數中的任何一個。
代碼以下:
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(); int n = nums2.size(); //cout << m << " " << n << endl; if ((m+n)%2 == 0) { //cout << "even" << endl; return (findKthNum(nums1, nums2, (m + n) / 2) + findKthNum(nums1, nums2, (m + n) / 2 + 1))/2; } else { //cout << "odd" << endl; return findKthNum(nums1, nums2, (m + n) / 2 + 1); } } int min(int a, int b) { if (a < b) { return a; } else { return b; } } double findKthNum(vector<int>& nums1, vector<int>& nums2, int k) { if (nums1.size() > nums2.size()) { return findKthNum(nums2, nums1, k); //注意nums1的size必定要比nums2小,否則會發生溢出錯誤 } //當m或者n爲0時 if (nums1.size() == 0) { if (k <= nums2.size()) { return nums2[k - 1]; } else { return nums2[nums2.size() - 1]; } } else if (nums2.size() == 0) { if (k <= nums1.size()) { return nums1[k - 1]; } else { return nums1[nums1.size() - 1]; } } if (k == 1) { return min(nums1[0], nums2[0]); } int offset_1 = min(k / 2, nums1.size()); int offset_2 = k - offset_1; vector<int> new_nums1, new_nums2; int i = 0; if (nums1[offset_1-1] == nums2[offset_2-1]) { return nums1[offset_1-1]; } else if (nums1[offset_1-1] < nums2[offset_2-1]) { for (vector<int>::iterator it = nums1.begin(); it != nums1.end(); it++) { if (i >= offset_1) { new_nums1.push_back(*it); } i++; } return findKthNum(new_nums1, nums2, k - offset_1); } else { for (vector<int>::iterator it = nums2.begin(); it != nums2.end(); it++) { if (i >= offset_2) { new_nums2.push_back(*it); } i++; } return findKthNum(nums1, new_nums2, k - offset_2); } } };