4. 寻找两个有序数组的中位数

在这里插入图片描述
解法一:暴力法
先将两个数组合并,然后根据奇数,还是偶数,返回中位数。时间复杂度不符合要求。
复杂度
时间复杂度:遍历全部数组O (m+n)
空间复杂度:开辟了一个数组,保存合并后的两个数组 O(m+n)

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

方法二:双指针

数组长度之和是奇数的时候,要看到索引为(m−1)/2的这个数,数组长度之和是偶数时要看到索引为m/2的这个数。有两种思路:
思路1(不采用):
不管长度之和是奇数还是偶数,直接先看到索引为(m−1)/2的这个数,如果是奇数,就可以返回了,如果是偶数,再往下看一个数;编码的时候,发现,会有一些冗余的代码,并且要考虑一些边界的问题,例如看索引为m/2的数的时候,可能 nums1 和 nums2 其中之一已经看完。
思路2(采用):那么不管奇数偶数,我都看到索引为m/2的这个数,那么索引为(m−1)/2 的这个数肯定看过了。
技巧:
1、我只关心最近看到的这两个数,那么我不妨将它们放置在一个长度为2的数组中,使用计数器模2的方式计算索引(这个技巧貌似叫做“滚动变量”),这样空间复杂度就可以降到常数。
2、在编码的时候,使用 counter 这个指针表示最后一次赋值的那个索引,初始化的时候,应该为-1,在每一次循环开始之前 ++。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size();
        int n=nums2.size();
        int mid=(m+n)>>1;   //中间的数的索引
        int cnt=-1,i=0,j=0;    //cnt为移动索引,i为nums1的索引,j为nums2的索引   
        int res[2]={0};      
        while(cnt<mid){
            cnt++;
            // 先写i和j遍历完成的情况,否则会出现数组下标越界
            if(i==m)
                res[cnt&1]=nums2[j++];
            else if(j==n)
                res[cnt&1]=nums1[i++];
            else if (nums1[i] < nums2[j])
                res[cnt&1] = nums1[i++];
            else 
                res[cnt&1] = nums2[j++];
        }
        // 如果 m + n 是奇数,mid就是我们要找的
        // 如果 m + n 是偶数,有一点麻烦,要考虑其中有一个用完的情况,其实也就是把上面循环的过程再进行一步
        if (((m+n)&1) == 1)
            return res[cnt&1];
        else
            return (double)(res[0]+res[1])/2;
        return -1;
    }
};

方法三:二分法

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
       //使nums1为短的数组,缩小查找范围
       if(nums1.size()>nums2.size())
           return findMedianSortedArrays(nums2,nums1);
        int m=nums1.size();     //在nums1的0~m中查找
        int n=nums2.size();
        int left=0,right=m;     //nums1的左右边界
        while(left<=right){
            int i=left+(right-left)/2;   //nums1的分界线
            int j=((m+n+1)>>1)-i;      //要保证左右数量一样,nums2的分界线可由nums1的分界线算出
            //处理边界情况
            int nums1LMax=i==0?INT_MIN:nums1[i-1];
            int nums1RMin=i==m?INT_MAX:nums1[i]; 
            int nums2LMax=j==0?INT_MIN:nums2[j-1];
            int nums2RMin=j==n?INT_MAX:nums2[j]; 
            if (nums1LMax <= nums2RMin && nums2LMax <= nums1RMin){    //找到
                if((m+n)%2) //总数奇数个
                    return max(nums1LMax,nums2LMax);
                else    //总数偶数个
                    return (max(nums1LMax, nums2LMax) + min(nums1RMin, nums2RMin))/2.0;
            }
            else if (nums2LMax > nums1RMin)
                left=i+1;	//左边界右移动
            else
                right=i-1;	//右边界左移动
        }
        return -1; //错误退出
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值