力扣4. 寻找两个正序数组的中位数

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

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays

1.暴力破解法
1.直接将两个有序数组合并到一起,不考虑有序。
2.将合并后的数组,进行手动排序。
3.排好序之后,直接找到中位数,那么这样的话,复杂度主要在排序的时间复杂度。
2.归并方式
首先将两个有序数组,合成一个有序数组,主要的时间复杂度,在这块。
合成的方法就是,两个元素一个一个的比较,放入数组中,若是其中有一个结束,则将另一个数组直接复制过去
合成一个数组之后,根据元素是奇数还是偶数个,将决定取两个元素还是一个元素,之后返回结果
这种解法:时间复杂度是O(m+n),空间复杂度是O(m+n)
现在这种做法,首先是将所有的都合并完成,之后在找到对应的位置。

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int arr[2000];
    int len1 = (int)nums1.size();
    int len2 = (int)nums2.size();
    int len = len1 + len2;
    int i1 = 0;
    int i2 = 0;
    int i3 = 0;

    while(i1 < len1 && i2 < len2) {
        if(nums1[i1] < nums2[i2]) {
            arr[i3] = nums1[i1];
            i1++;
            i3++;
        } else {
            arr[i3] = nums2[i2];
            i2++;
            i3++;
        }
    }

    if(i1 == len1) {
        for(int i = i2; i < len2; i++) {
            arr[i3] = nums2[i];
            i3++;
        }
    }

    if(i2 == len2) {
        for(int i = i1; i < len1; i++) {
            arr[i3] = nums1[i];
            i3++;
        }
    }

    // for(int i = 0; i < len; i++) {
//printf("%d ", arr[i]);
    //  }

    if(len % 2 == 0) {
        int o1 = len / 2 - 1;    //找到的对应位置1
        int o2 = o1 + 1;
        return (arr[o1] + arr[o2]) / 2.0;
    } else {
        double o1d = len / 2.0;
        int o1 = (int)ceil(o1d) - 1;
        return arr[o1];
    }
}

3.归并方式优化
下面这种方法是有两个有序数组,我们需要做的是一个一个的进行比较,取值小的。
若是有一组找完了,则可以直接去另一组找。这里奇数和偶数个还有些差别,奇数个找一个,偶数找两个。
这个程序的时间复杂度也是O(m+n),空间复杂度O(m+n),和上一种方法速度差不多,有可能快些。
但是这种方法要判断的逻辑有很多,下面的代码还是有很多逻辑没有处理完。
现在这种做法,我看完官方解释,其实就是上一个做法的优化版本,我之前的分析有问题,只是,处理到一半
就不在处理,找到对应的位置后,就停止。并不能改变时间复杂度
首先,判断奇数和偶数,其次找到对应的位置,若找到位置则返回结果。
这种做法,我想着特别好做,但是没写出代码来,还是水平太差了。
4.二分查找法解法,参考力扣官方题解
二分查找法解法,参考力扣官方题解
1.首先给定两个有序数组,返回第k个元素
2.这里两个数组都是有序的,我们要返回第k个元素的值,可以想到二分查找的方法
3.这里先判断pivot1=nums1[k/2-1],pivot2=nums2[k/2-1],其中比pivot1小的元素有k/2-1,而比pivot2小的元素有k/2-1
4.min(pivot1,pivot2),这两个元素的较小值,最多只能是k-1个元素,所以包含最小者和[0, k/2-1]都不可能是第k个最小值,可以直接排除
5.特殊情况,若是nums1[k/2-1]和nums2[k/2-1]越界,那么选择对应数组的最后一个,k排除的个数,要和实际减少的相同
6.如果一个数组为空,那么直接返回另一数组中第k小的元素
7.如果k=1,返回两个数组元素的最小值

//这里nums1和nums2是有序的,找到第k个元素,是第k个,而不是下标
int getKElement(const vector<int> &nums1, const vector<int> &nums2, int k) {
    int m = nums1.size();
    int n = nums2.size();
    int index1 = 0, index2 = 0;  //index1和index2是nums1和nums2的起始坐标位置,因为升序的,所以只会排除左边

    while(true) { //index1和index2是分别包含的边界,要找到对应的k个,这里k不是下标
        //边界情况
        if(index1 == m) {  //这里index1==m的话本数组就没有了,就直接在另一个数组中取
            return nums2[index2 + k - 1];
        }

        if(index2 == n) {
            return nums1[index1 + k - 1];
        }

        //index1和index2都包含
        if(k == 1) {   //如果找第一个,那么对应下面的结果的两个数组中最小的一个
            return min(nums1[index1], nums2[index2]);
        }

        //正常情况
        //这里,包含index元素,第k/2个元素,所以应该减1
        int t_index1 = min(index1 + k / 2 - 1, m - 1);
        int t_index2 = min(index2 + k / 2 - 1, n - 1);
        int pivot1 = nums1[t_index1];
        int pivot2 = nums2[t_index2];

        //t_index1这里已经不符合了
        if(pivot1 <= pivot2) {
            k -= (t_index1 -  index1 + 1);  //减去对应的个数
            index1 = t_index1 + 1;
        } else {
            k -= (t_index2 - index2 + 1);
            index2 = t_index2 + 1;
        }
    }
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int length = nums1.size() + nums2.size();

    //这里判断偶数和奇数个长度
    if(length % 2 == 0) {
        //这里,如果是偶数个长度
        return (getKElement(nums1, nums2, length / 2) + getKElement(nums1, nums2, length / 2 + 1)) / 2.0;
    } else {
        //这里,如果是奇数个长度
        return getKElement(nums1, nums2, (length + 1) / 2);
    }
}
/*
特别注意:
1.一个数组为空的情况,k=1的情况
2.k的数量每次都要减少,但是比较的时候,index1和index2的下标在比较的时候,需要改变
3.但是,真正变动的时候,只需要变动小的那个index,而另一个不需要index不需要变动
*/
int main() {
    vector<int> list1 = {1, 2};
    vector<int> list2 = {3, 4};
    double num = findMedianSortedArrays(list1, list2);
    printf("%lf", num);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值