leetcode-day01-两个排序数组的中位数

4.两个排序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

示例 1:

nums1 = [1, 3]
nums2 = [2]

中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

中位数是 (2 + 3)/2 = 2.5


解决方法1:

    这个方法其实是不符合时间复杂度的方法,但也是我们最常想起来的方法。

    我们可以将两个数组进行合并,并进行排序,然后就可以轻松得到其中位数。我们这儿采用的排序方法是归并排序,其时间复杂度为O(m*n)

代码:

//归并排序
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 i = 0;
        int j = 0;
        vector<int> ans;
        while (i < m && j < n) {
            if (nums1[i] <= nums2[j]) {
                ans.push_back(nums1[i]);
                i++;
            } else {
                ans.push_back(nums2[j]);
                j++;
            }
        }
        if (i < m) {
            for (; i < m; i++)
                ans.push_back(nums1[i]);
        } else if (j < n) {
            for (; j < n; j++)
                ans.push_back(nums2[j]);
        }
        int len = ans.size();
        if (len%2 != 0)
            return 1.0*ans[len/2];
        return (ans[len/2]+ans[len/2-1])/2.0;
    }
};

解决方法2:

    为了满足题目对时间复杂度的要求,我们这儿可以采用二分查找法。逐步排除掉不可能出现中位数的区间,最后找到所求的中位数。这种解法的主要思想就是: 
如果数组a的中位数小于数组b的中位数,那么整体的中位数只可能出现在a的右区间加上b的左区间之中; 
如果数组a的中位数大于等于数组b的中位数,那么整体的中位数只可能出现在a的左区间加上b的右区间之中。 

关键就是利用分治的思想逐渐缩小a的区间和b的区间来找到中位数。

代码:

//二分查找
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;
        }
/* 如果m+n为偶数的时候,即中位数是中间两个的平均数,total和total2分别表示这两个数 
* 如果m+n为奇数的时候,即中位数是中间那个数,total和total2相等,均表示中间那个数 
*/ 
        int total = (m+n+1)/2;
        int total2 = (m+n+2)/2;

        return (find_kth(nums1,0,nums2,0,total)+find_kth(nums1,0,nums2,0,total2))/2.0;
    }
    //这个函数就是用于寻找两个数组合并之后第k位的数(下标为k-1) 
    double find_kth(vector<int> a, int a_begin, vector<int> b, int b_begin, int k) {
    //如果 a_begin和b_begin 在对应数组的最后位置上,则需要返回另外一个数组的下标为k-1的数即可 
        if (a_begin > a.size()-1)
            return b[b_begin+k-1];
        if (b_begin > b.size()-1)
            return a[a_begin+k-1];
        //如果k==1,返回两个数组起始数据中较小的那一个 
        if (k == 1)
            return min(a[a_begin],b[b_begin]);


        int mid_a = INT_MAX;
        int mid_b = INT_MAX;
        //分别找到两个数组中下标为对   应起始下标  +  k/2-1  的位置 
        if (a_begin+k/2-1 < a.size())
            mid_a = a[a_begin+k/2-1];
        if (b_begin+k/2-1 < b.size())
            mid_b = b[b_begin+k/2-1];
// 
        if (mid_a < mid_b)
            return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
        return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值