這道題目和PAT上的1029是同一題。可是PAT1029用O(m+n)的時間複雜度(題解)就能夠,這道題要求是O(log(m+n))。html
這道題花費了我一個工做日的時間來思考。由於是log於是一直思考如何進行二分,想着是兩個vector分別二分,但一直想不到合適的解法,就是無窮盡的if else數組
後來看了題解。思路是從兩個有序數組中尋找第k小的數。spa
<1>花了很長時間在調試上,結果發現是少了一個return,期間還不停懷疑本身寫遞歸的能力。。。要被本身戰勝了,調代碼真是一件細小卻很耗費心神的事情。指針
<2>對vector的使用也是醉了。調試
思路以下:code
咱們先假設nums1和nums2數組中元素個數都是大於 k/2 的,且從 0 開始編號,那麼咱們比較 a = nums1[k/2 - 1] 和 b = nums2[k/2 - 1]。htm
(1)若是 a < b 那麼 nums1[0] 到 nums1[k/2 - 1] 這 k/2 個數在合併後的有序數組中,必定在第 k 小的數左邊。爲何呢?blog
咱們發現,nums1數組中比 a 小的數一共是 k/2 - 1 個。nums2數組中比 a 小的數最多有 k/2 - 1 個。於是合併之後比 a 小的數最多有k/2 - 1 + k/2 - 1 < k - 2。遞歸
也就是說 a 最可能是第 k-1 小的數。因此說nums1數組前 k/2 個數能夠剔除了。get
(2)若是 a > b 同理,剔除掉 nums2數組前 k/2 個數。
(3)若是 a = b,a 即爲所求。
每次剔除掉 k 一半個元素,於是時間複雜度是O(logk),對於此題,k = (m+n)/2 因此時間複雜度是O(log(m+n))
考慮實際狀況:
若是nums1和nums2數組中元素個數不足 k/2 個的話,通常狀況下,咱們只須要知足二者前面的總數目爲 k 便可,原理和上述的原理是相似的,再也不贅述。
此外還須要考慮特殊狀況,
(1)一個數組爲空,則放回另外一個數組的第 k 大;
(2)k==1則直接返回min(nums1[0],nums2[0])。
在實際實現的時候,因爲輸入是vector,它是一個動態數組,能夠實時增長或刪除元素,可是沒法向普通數組/指針同樣任意指定起始位置和結束爲止,於是只好使用了刪除操做
erase(iter1,iter2),刪除[iter1,iter2)之間的元素。
1 class Solution { 2 public: 3 double findkth(vector<int>& nums1,vector<int>& nums2, int k) 4 { 5 int m = nums1.size(),n = nums2.size(); 6 if(m > n) 7 return findkth(nums2,nums1,k);//error 1. forget the "return"; 8 if(m == 0) 9 return double(nums2[k - 1]);//error 2. write as nums2[n - 1]; 10 if(k == 1) 11 { 12 return double(min(nums1[0],nums2[0])); 13 } 14 int pa = min(k / 2,m), pb = k - pa; 15 if(nums1[pa - 1] < nums2[pb - 1]) 16 { 17 nums1.erase(nums1.begin(),nums1.begin() + pa); 18 return findkth(nums1,nums2,k - pa); 19 } 20 else if(nums1[pa - 1] > nums2[pb - 1]) 21 { 22 nums2.erase(nums2.begin(),nums2.begin() + pb); 23 return findkth(nums1,nums2,k - pb); 24 } 25 else 26 return double(nums1[pa - 1]); 27 } 28 double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { 29 int len1 = nums1.size(),len2 = nums2.size(); 30 int len = len1 + len2; 31 vector<int> cop1(nums1),cop2(nums2); 32 if(len % 2) 33 { 34 return findkth(nums1,nums2,len / 2 + 1); 35 } 36 else 37 { 38 double t1=findkth(nums1,nums2,len / 2),t2=findkth(cop1,cop2,len / 2 + 1); 39 return (t1 + t2) / 2; 40 } 41 } 42 };
刪除vector的元素須要①額外備份一下數組,②刪除操做。無謂的耗時,於是從新實現成手動標記數組的起始位置。只須要在上面實現方法的基礎上 + star就能夠了,原理都是同樣的。
1 class Solution { 2 public: 3 double findkth(vector<int>& nums1,int st1,int ed1,vector<int>& nums2, int st2,int ed2,int k) 4 { 5 int m = ed1 - st1,n = ed2 - st2; 6 if(m > n) 7 return findkth(nums2,st2,ed2,nums1,st1,ed1,k);//error 1. forget the "return"; 8 if(m == 0) 9 return double(nums2[st2 + k - 1]);//error 2. write as nums2[n - 1]; 10 if(k == 1) 11 { 12 return double(min(nums1[st1],nums2[st2])); 13 } 14 int pa = min(k / 2,m), pb = k - pa; 15 if(nums1[st1 + pa - 1] < nums2[st2 + pb - 1]) 16 { 17 return findkth(nums1,st1 + pa,ed1,nums2,st2,ed2,k - pa); 18 } 19 else if(nums1[st1 + pa - 1] > nums2[st2 + pb - 1])//error 3. forget the "st2 +"; 20 { 21 return findkth(nums1,st1,ed1,nums2,st2 + pb,ed2,k - pb); 22 } 23 else 24 return double(nums1[st1 + pa - 1]); 25 } 26 double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { 27 int len1 = nums1.size(),len2 = nums2.size(); 28 int len = len1 + len2; 29 if(len % 2) 30 { 31 return findkth(nums1,0,len1,nums2,0,len2,len / 2 + 1); 32 } 33 else 34 { 35 double t1 = findkth(nums1,0,len1,nums2,0,len2,len / 2),t2 = findkth(nums1,0,len1,nums2,0,len2,len / 2 + 1); 36 return (t1 + t2) / 2; 37 } 38 } 39 };