4 median-of-two-sorted-arrays
第四題評級是hard,看似很簡單的題目著實沒有那麼容易做,主要原因在於時間複雜度的要求非常嚴格,基本上陣列的題目,只要已經拍好了順序,就必須在logN的複雜度下解決,當然後臺的檢測沒有那麼嚴格,O(n)也能通過,而為了而實現logN的複雜度,我也是在網上看了好久的答案,自己手推了一遍,才AC掉。
答題的思路是這樣的:
1、兩個有序陣列,總共有多少個數已知,這道題的本質就變成了第K個小數是哪個的問題。
2、因為本題要求中位數,奇數和偶數個數之間是不同的,所以,如果是偶數個數字,需要求出第K/2個和第K/2+1個兩個數。
3、假設有我現在有一個函式能求出來第K個數字,則主題函式的部分因該是這樣的:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int numsize1 = nums1.size(); int numsize2 = nums2.size(); double median = 0; vector<int> num1t = nums1; vector<int> num2t = nums2; median = findKthnum(num1t,num2t, (numsize1+numsize2)/2+1); if (!((numsize1 + numsize2)&0x1)){ num1t = nums1; num2t = nums2; median += findKthnum(nums1, nums2, (numsize1+numsize2)/2); median = median/2; } return median; }
至於說findKthnum這個函式如何實現,我們現在先不用管,至少目前我們思路上很清楚,知道資料總長度,然後針對總長度是奇數和偶數兩種情況,分別計算。整個函式的複雜度也就取決於findKthnum這個函式。
<1> 、我們可以在紙上畫出一種比較理想的情況,就是兩個陣列各自的中位數是一模一樣的,如果出現那樣的情況,該數就是中位數,因為在該數兩邊,比其小的和比其大的數目一樣。
<2>、假設nums1的中位數是m1,nums2的中位數是m2,如果m1比m2小,那麼這兩個陣列的中位數就在m1和m2中間,m1<m<m2。
<3>、我們說這道題的本質是求第K小的數是多少,那是不是把前面K-1個數捨棄,剩下的數中第一個就是我們的目標數值。結合<2>中的說法,我們知道第K小的數在m1到m2之間,那m1之前的數是不是就可以捨棄了,那是肯定的,此後每次都是做這樣的操作,每次都是將中位數小的陣列剩餘所有元素中的一半捨棄,所以時間複雜度是logN,最終捨棄K-1個元素即可。
以下是程式碼,其中要考慮較短陣列剩餘長度和總長度一半的比較,防止越界。
int findKthnum (vector<int>& nums1, vector<int>& nums2, int k) {
if (nums1.size() > nums2.size()) {
return findKthnum (nums2, nums1, k);
}
if (nums1.size() < 1) {
return nums2[k-nums1.size()-1];
}
if (k==1) {
return min(nums1[0], nums2[0]);
}
int smsize1 = nums1.size();
smsize1 = min(k/2, smsize1); int smsize2 = k-smsize1;
if (nums1[smsize1-1] > nums2[smsize2-1]) {
nums2.erase(nums2.begin(), nums2.begin()+smsize2);
return findKthnum (nums1, nums2, k-smsize2);
} else if (nums1[smsize1-1] < nums2[smsize2-1]) {
nums1.erase(nums1.begin(), nums1.begin()+smsize1);
return findKthnum (nums1, nums2, k-smsize1);
} else {
return nums1[smsize1-1];
}
}