leetcode題目連接
設給出的兩個已從小到大排序的數組爲nums1和nums2,size1=nums1.size(),size2=nums2.size()。
分析題目能夠知道,要找到中位數,最好能從2個已排序數組中找到第k小的數字,後者是更具通常性的問題。算法
咱們固然能夠先merge這兩個已經排序的數組,而後直接返回合併後數組的第k個數字。時間複雜度爲O(size1+size2)。可是這個時間複雜度超出了題目限制的O(log (size1+size2))。數組
合併兩個數組太耗時了,咱們不能這樣作。
咱們的思路是,不斷刪掉數組中確定不是第k小的那些數字,從而可以不斷地減少數組,在這個過程當中,咱們要找的那個數字的序號(k)也會不斷地減少。
數組中的哪些數字能夠刪除呢?
讓咱們假設k是4:
nums1: [a1, a2, a3, ...]
nums2: [b1, b2, b3, ...]
若是a2<b2,那麼a2確定能夠刪除。由於有可能比a2小的數字只有:函數
所以,a2最多隻能是第3小的數字,確定比咱們要找的第4數字要小!從而a2,以及比a2還小的a1,均可以刪除。code
刪除這兩個數字之後,問題變成了:
nums1: [a3, ...]
nums2: [b1, b2, b3, ...]
從以上兩個已排序數組中找出第2小的數字。(k已經變了,由於咱們已經刪除了兩個比咱們要找的那個數字還小的數字。)排序
同理,咱們能夠刪除a3和b1中較小的那個數字,而後問題變成從剩餘數字中找到第1小的數字。這個問題不就簡單了嗎?遞歸
推廣以上方法,咱們能夠寫出一個get_kth_smallest
函數:ip
class Solution { public: // findMedianSortedArrays只是簡單地調用get_kth_smallest。後者纔是算法的核心。 double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int total_size = nums1.size()+nums2.size(); if (0 == total_size) throw std::invalid_argument( "received empty arrays" ); if (total_size%2 == 0) { return (get_kth_smallest(nums1, nums2, total_size/2)+get_kth_smallest(nums1, nums2, total_size/2+1))/2.0; } else { return get_kth_smallest(nums1, nums2, total_size/2+1); } } int get_kth_smallest(vector<int> nums1, vector<int> nums2, int k) { // 保證nums1.size() <= nums2.size(),方便分析 if (nums1.size() > nums2.size()) return get_kth_smallest(nums2, nums1, k); if (nums1.empty()) return nums2[k-1]; if (1 == k) return nums1[0] < nums2[0]? nums1[0]:nums2[0]; // 在nums1和nums2中分別取第k/2個數字。固然,若是k/2已經超出數組邊界,咱們只取數組最後的那個數字。 int k1 = min(static_cast<int>(nums1.size()), k/2); int k2 = min(static_cast<int>(nums2.size()), k/2); if (nums1[k1-1] < nums2[k2-1]) { // 若是nums1[k1-1] < nums2[k2-1],說明nums1[k1-1]小於咱們要找的第k小的數字。 nums1.erase(nums1.begin(), nums1.begin()+k1); return get_kth_smallest(nums1, nums2, k-k1); } else { // 若是nums1[k1-1] > nums2[k2-1],說明nums2[k2-1]小於咱們要找的第k小的數字。 // 若是nums1[k1-1] == nums2[k2-1],說明nums2[k2-1]小於或等於咱們要找的第k小的數字。即便nums2[k2-1]等於咱們要找的第k小的數字,咱們依然能夠刪掉它,由於還有nums1[k1-1]和它相等呢! nums2.erase(nums2.begin(), nums2.begin()+k2); return get_kth_smallest(nums1, nums2, k-k2); } } };
注意到get_kth_smallest中沒有循環語句,只有遞歸,所以時間複雜度徹底取決於get_kth_smallest
的調用次數。leetcode
get_kth_smallest
都會使k減少一半。k減少爲1時獲得結果。從而時間複雜度爲O(log_2(k))。由於k<size1+size2,因此時間複雜度符合題目要求。