LeetCode/寻找两个正序数组中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数

1. 辅助空间暴力法

将两数组合并,分奇偶取中位数

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        vector<int> merge;
        int i =0; int j=0;
        while(i<m&&j<n){
            if(nums1[i]<=nums2[j]){ merge.push_back(nums1[i]); i++;}
            else {merge.push_back(nums2[j]); j++;}
        }
        while(i<m){merge.push_back(nums1[i]); i++;}
        while(j<n){merge.push_back(nums2[j]); j++;}
        if((m+n)%2==0) return (merge[(m+n)/2-1]+ merge[(m+n)/2])/2.0;
        else return merge[(m+n)/2];
    }
};

2. 双指针暴力法

不需要辅助空间,让两指针边比较边移动,到中间位置即可,分奇偶输出结果
这里不要单纯记录指针,单纯记录指针的话,最后获得结果的时候,既要讨论是否为空集
又要讨论两指针哪个数为后一个数,以及求在偶数的情况下前一个数的位置,非常麻烦
干脆每次遍历都记录更新两个对应值,最后直接得到中位数

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        int len = m+n;
        int left =-1; int right=-1;//记录中位数值,避免单纯记录指针的分类讨论,避免处理一数组为空集
        int start1 = 0; int start2 = 0;//两指针初始位置
        for(int i=0;i<=len/2;i++){//直接遍历len/2 + 1次 ,不用指针进行跳出,避免分类讨论
            left = right;
            //处理边界条件和移动条件
            if(start1 < m && (start2 >= n || nums1[start1] < nums2[start2]))
                {right = nums1[start1]; start1++;}
            else  {right = nums2[start2]; start2++;}
        }
        if(len%2==0) return (left + right) / 2.0;
        else return right;
    }
};

3. 二分法

因为已经是有序的,合理使用二分性能最好
关键在于如何通过二分使问题规模变小,容易判断通过取两数组中间位置进行比较
可以排除掉较小数前面所有数,但对剩下的数来说问题发生了改变,不再是求中位数
其实求中位数本质上是求第len/2小的数,所以可以写求第k小的数
在排除一部分数后,求取的k也随之改变,注意递归的边界条件

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        int left = (m+n+1)/2;
        int right = (m+n+2)/2;
    return (getKth(nums1,0,m-1,nums2,0,n-1,left)+getKth(nums1,0,m-1,nums2,0,n-1,right))*0.5;
    }

    int getKth(vector<int>& nums1,int start1,int end1,
    vector<int>& nums2,int start2,int end2,int k){
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        //处理边界
        if (len2 == 0) return nums1[start1 + k - 1];//空集的情况
        if (len1 == 0) return nums2[start2 + k - 1];//空集的情况
        if (k == 1) return min(nums1[start1], nums2[start2]);//k规模缩减至1
        int i = start1 + min(len1, k / 2) - 1;//取中间值或边界
        int j = start2 + min(len2, k / 2) - 1;//取中间值或边界
         if (nums1[i] > nums2[j])//
            //缩小问题规模,数组二从j+1开始,其前面的数必然不是第k小,同时k发生改变
            return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
            //否则从数组一i+1开始,k发生改变
        else return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));

    }
};
posted @ 2022-06-17 22:55  失控D大白兔  阅读(31)  评论(0编辑  收藏  举报