LeetCode-第三天

又是得空的一天开始打卡

感冒依旧没好,继续打卡!

题目描述

在这里插入图片描述
题目意思很简单,就是从两个已经排好序的数组中,找出中位数,中位数的意思想必小学都已经学过了。本身题目很简单,但是题目要求的时间复杂度却是一个难点,当然很明显,要实现如此复杂度,二分法很合适!

解法

  • 暴力解法
    这个方法很佛系,虽然不满足题目的复杂度O(log(m+n))但是依旧提交成功,并且耗时也不多,虽然没有双百…
    (1)代码
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int count = nums1.size()+nums2.size();
        int i =0;
        int j=0;
        int foreNum=0;
        int nowNum=0;
        int num=0;
        int s1 =i< nums1.size()?nums1.at(i):numeric_limits<int>::max();
        int s2 = j < nums2.size()?nums2.at(j):numeric_limits<int>::max();
        while(true){
            foreNum = nowNum;
            if(s1 > s2 ){
                nowNum = s2;
                s2 = j < nums2.size()-1?nums2.at(++j):numeric_limits<int>::max();
            }
            else{
                nowNum = s1;
                s1 = i< nums1.size()-1?nums1.at(++i):numeric_limits<int>::max();
            }
            if(num == count /2){
                return count%2==0?(foreNum+nowNum)/2.0:nowNum;
            }
            num++;
        }   
    }

时间复杂度大概应该是O((m+n)/2),思路很简单,就是单纯的将两个集合里的数一个个取出,然后比较,按从小到大的顺序,当到达中位数的位置时,输出结果。
(2)结果:
在这里插入图片描述
虽然没有双百,但是暴力解法能到这样我已经很满足了!

  • 二分法
    根据题目要求的时间复杂度,看到的第一想法应该就是用二分法(排除那些明显不可能的结果,就如剪枝)来做,思考了一下(顺便借鉴了点前人的经验),废话不多说先上代码,如下:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int count = nums1.size() + nums2.size();
        if (count % 2 == 1) {
            return getKthElement(nums1, nums2, (count + 1) / 2);
        }
        else {
            return (getKthElement(nums1, nums2, count / 2) + getKthElement(nums1, nums2, count / 2 + 1)) / 2.0;
        }
    }

    //找第k小
    int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
        int m = nums1.size();
        int n = nums2.size();
        int index1 = 0, index2 = 0;
        while (true) {
            // 边界情况
            if (index1 == m) {
                return nums2[index2 + k - 1];
            }
            if (index2 == n) {
                return nums1[index1 + k - 1];
            }
            if (k == 1) {
                return min(nums1[index1], nums2[index2]);
            }

            // 正常情况
            int newIndex1 = min(index1 + k / 2 - 1, m - 1);
            int newIndex2 = min(index2 + k / 2 - 1, n - 1);
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];
            if (pivot1 <= pivot2) {
                k -= newIndex1 - index1 + 1;
                index1 = newIndex1 + 1;
            }
            else {
                k -= newIndex2 - index2 + 1;
                index2 = newIndex2 + 1;
            }
        }
    }

解释(总结了一下经验,这部分并非原创):

假设两个有序数组分别是 A 和 B。要找到第 k 个元素,我们可以比较 A[k/2−1] 和 B[k/2−1],其中 // 表示整数除法。由于 A[k/2−1] 和B[k/2−1] 的前面分别有 A[0…k/2−2] 和 B[0…k/2−2],即k/2−1 个元素,对于A[k/2−1] 和 B[k/2−1] 中的较小值,最多只会有 k/2-1+(k/2−1)≤k−2 个元素比它小,那么它就不能是第 k 小的数了。

因此我们可以归纳出三种情况:

(1)如果 A[k/2−1]<B[k/2−1],则比 A[k/2−1] 小的数最多只有 A 的前 k/2−1 个数和 B 的前k/2−1 个数,即比A[k/2−1] 小的数最多只有 k−2 个,因此 A[k/2−1] 不可能是第 k 个数,A[0] 到A[k/2−1] 也都不可能是第 k 个数,可以全部排除。
(2)如果 A[k/2−1]>B[k/2−1],则可以排除 B[0] 到 B[k/2−1]。
(3)如果 A[k/2−1]=B[k/2−1],则可以归入第一种情况处理。

那么就可以根据这个方法实现O(log(m+n))的时间复杂度。
附上原解:二分法寻找两个正序数组的中位数
运行结果如下:
在这里插入图片描述
其实相对来说,系统所用的测试数组并不太大,表现出的时间复杂度区别不太大,但仍很快!!!

这个方法相对来说,我用的并不多,看来还是得再熟练熟练,多练几次。

今天这个题比较难,自己近九点才开始写(下次一定要在七点半就开始写),所以就只写了一个题目!!!

睡觉睡觉!!!

明天好好把握时间!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值