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

};
posted @ 2021-11-09 22:03  pxlsdz  阅读(38)  评论(0编辑  收藏  举报