LeetCode4:兩個排序數組的中位數

問題

/*
 * @lc app=leetcode.cn id=4 lang=cpp
 *  * [4] 尋找兩個有序數組的中位數
 *  * https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/
 *  * algorithms
 * Hard (33.60%)
 * Total Accepted:    37K
 * Total Submissions: 110.2K
 * Testcase Example:  '[1,3]\n[2]'
 *  * 給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。
 * 
 * 請你找出這兩個有序數組的中位數,並且要求算法的時間複雜度爲 O(log(m + n))。
 * 
 * 你可以假設 nums1 和 nums2 不會同時爲空。
 * 
 * 示例 1:
 * 
 * nums1 = [1, 3]
 * nums2 = [2]
 * 
 * 則中位數是 2.0
 * 
 * 
 * 示例 2:
 * 
 * nums1 = [1, 2]
 * nums2 = [3, 4]
 * 
 * 則中位數是 (2 + 3)/2 = 2.5
 * 
 * 
 */

思路1:歸併排序,合併有序數組,時間複雜度O(m+n),不符合要求
思路2:看到時間複雜度O(log(m+n)),首先可以想到二分法(分治思想)

  • 把找中位數轉化爲找第 (m+n+1)/2 和 第 (m+n+2)/2 小元素的平均(這樣不用考慮奇偶的問題)

  • 二分思想設計find_kth函數 假定整體數組c中歐前k個元素一半k/2在數組a,一半k/2在數組b

    • 如果a[k/2] < b[k/2] 那麼 a[0]<=a[1]<=…<=a[k/2] <= b[k/2] 且 b[0]<=b[1]<=…<=b[k/2] 說明b[k/2] 至少是c中第k小的元素,所以a[0-k/2]都小於我們的目標值,可以去掉a[0-k/2],然後在剩下的元素中找第k/2小
    • 同理如果a[k/2] > b[k/2] 所以b[0-k/2]都小於我們的目標值,可以去掉b[0-k/2],然後在剩下的元素中找第k/2小
  • 如果數組a中個數不夠k/2,那麼b中小於目標元素的個數一定大於k/2,所以可以去掉b中前k/2小的元素,然後在剩下的元素中找第k/2小

  • 同理如果數組b中個數不夠k/2,那麼a中小於目標元素的個數一定大於k/2,所以可以去掉a中前k/2小的元素,然後在剩下的元素中找第k/2小

完整代碼如下

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {

        int m = nums1.size();
        int n = nums2.size();
        if (nums1.empty()) {
            if (n%2 != 0)
                return 1.0*nums2[n/2];
            return (nums2[n/2]+nums2[n/2-1])/2.0;
        }
        if (nums2.empty()) {
            if (m%2 != 0)
                return 1.0*nums1[m/2];
            return (nums1[m/2]+nums1[m/2-1])/2.0;
        }

        int total = (m+n+1)/2;
        int total2 = (m+n+2)/2;
        // 轉換爲在兩個有序數組中尋找第k小元素(從1計數) (m+n+1)/2  (m+n+2)/2
        return (find_kth(nums1,0,nums2,0,total)+find_kth(nums1,0,nums2,0,total2))/2.0;
    }
    double find_kth(vector<int> a, int a_begin, vector<int> b, int b_begin, int k) {
        // a中無元素 b有序 直接在b中取第k小元素
        if (a_begin > a.size()-1)
            return b[b_begin+k-1];
        if (b_begin > b.size()-1)
            return a[a_begin+k-1];
        // 第1小元素 就是找ab中最小元素的最小值
        if (k == 1)
            return min(a[a_begin],b[b_begin]);
        if (a_begin+k/2-1 < a.size() && b_begin+k/2-1 < b.size()){
            if(a[a_begin+k/2-1] < b[b_begin+k/2-1])
                return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
            else
                return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
        }
        else if(a_begin+k/2-1 < a.size()){
            return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
        }else{
           return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
        }

在這裏插入圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章