1. 程式人生 > 其它 >LeetCode4. 尋找兩個正序陣列的中位數 思維和分治

LeetCode4. 尋找兩個正序陣列的中位數 思維和分治

LeetCode4. 尋找兩個正序陣列的中位數

題意

給定兩個大小分別為 mn 的正序(從小到大)陣列 nums1nums2。請你找出並返回這兩個正序陣列的 中位數

演算法

問題轉變為尋找兩個正序陣列中第k小的數是什麼。

假設m,n >= k/2,我們分別在nums1nums2陣列分別選取k/2個數,

  • nums1[k/2 - 1] > nums2[k/2 - 1],可以排除nums2k/2個數肯定不是中位數,接下來需要尋找第k - k/2數即可。
  • nums1[k/2 - 1] <= nums2[k/2 - 1],可以排除nums1k/2個數肯定不是中位數,接下來需要尋找第k - k/2
    數即可。

假設m < k/2,則我們從nums1中取m個元素,從nums2中取 k/2 個元素(由於 k=(n+m)/,因此 m,n 不可能同時小於 k/2.):

  • nums1[m - 1] > nums2[k/2 - 1],可以排除nums2k/2個數肯定不是中位數,接下來需要尋找第k - k/2數即可。
  • nums1[m - 1] <= nums2[k/2 - 1],可以排除nums1中的所有數肯定不是中位數,答案為nums2[k - m -1]數即可。

終止條件& 特殊條件:

  1. 因為兩個陣列不一定等長,程式交換一下為確保nums1.size() <= nums2.size()
    即可,最後如果nums1全部用完,放回nums2[j+k]即可。
  2. nums1 有可能不夠k/2個數,需要特殊判斷
  3. if(k == 1),返回 min(nums1[i], nums2[j])

時間複雜度分析: \(k=(m+n)/2\) ,且每次遞迴 \(k\) 的規模都減少一半,因此時間複雜度是 \(O(\log(m+n))\),

class Solution {
public:
    int dfs(vector<int>& nums1, int i, vector<int>& nums2, int j, int k){
        if(nums1.size() - i > nums2.size() - j) return dfs(nums2, j, nums1, i, k);
        if(nums1.size() == i) return nums2[j + k - 1];
        if(k == 1){
            if(nums1.size() == i) return nums2[j + k - 1];
            else return min(nums1[i], nums2[j]);
        }
        int a = min((int)nums1.size(), i + k / 2) - 1, b = j + k / 2 - 1;
        if(nums1[a] > nums2[b]) 
            return dfs(nums1, i, nums2, b + 1, k - (b - j + 1));
        else 
            return dfs(nums1, a + 1, nums2, j, k - (a - i + 1));
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size() + nums2.size();
        if(n & 1){
           return 1.0 * dfs(nums1, 0, nums2, 0, n / 2 + 1);
        }else{
         return (dfs(nums1, 0, nums2, 0, n / 2) + dfs(nums1, 0, nums2, 0, n / 2 + 1)) / 2.0;
        }
        
    }

};