1. 程式人生 > >4 median-of-two-sorted-arrays

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];
        }
    }