LeetCode算法问题3 —— Median of Two Sorted Arrays

问题描述

这里写图片描述

问题要求我们找到给定的两个已排序的数组组合在一起的中位数(median)。

关于时间复杂度为O(log(m+n))的要求,我还没达到,但是想到了一个不错的方法,先记录下来。

说到中位数的计算,牵扯到这个数列的长度:

  • 为奇数:就取中间的数
  • 为偶数:取中间两位数的平均值

那么如何找到中位数呢?笨办法当然是乖乖地把两个数组的数都取出来然后排序,最后再取中位数。

但是我突然注意到了sorted,那么完全就不用把两个数组的数都放到一个新数组中做排序然后再取中位数。我的想法是分别给两个数组指针,然后依靠比大小来遍历(类似于排序),以数组[1,6],[2,3,5]为例详解:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

挑选中位数自然就在这个排序中选取即可。

那么找到中位数之前我们需要知道什么呢:

  • ifLengthOdd(bool类型)判断这一系列数是否是奇数长度
  • medianPos(int类型)确定中心位置在哪
  • answer(double类型)作为问题的答案(先做加法——中间两位数相加,当然,这是在长度为偶数情况下;再做除法——偶数情况下除以2)

定义与获取自然就是这样的:

这里写图片描述

当然我们也要考虑给定的一个数组是空的情况下(vector类型存储)

这里写图片描述

排除空数组情况后,我们开始遍历,出于vector类型的考虑,且一开始是以指针来分析的,所以我打算用迭代器,但后来想想用下标访问或许更方便,因此对于两个数组,各需要一个pos1pos2来记录当前所指位置,还需要一个currentPos来表示我们当前是处在排序后总数组的哪一个位置,这样便于找到中位数,自然,找到中位数后,后面的排序我们并不关心。

我们首先以数组nums1作为参考,pos1何时才会向后移动呢?只有两种情况:

  1. nums1还有数没遍历完,且nums1当前所指的数小于nums2当前所指的数
  2. nums2已经遍历完了

否则就是pos2向后移动。当然,每次都相当于取出了一个数并排序,因此currentPos需要加1。

如果长度为奇数,median表示的就是中位数,如果长度为偶数,median表示的是其中两个数的第一个,至于下一个数我们在找到第一个数后再考虑,因此可以先把这个数传给answer,我写的循环遍历如图

这里写图片描述

最后再判断是否需要第二个数即可,这里nums1[pos1]nums2[pos2]还要再比较一次

这里写图片描述

这样就得到了中位数。

这个算法比较易于理解,好处是不用专门再开一个数组把这两个数组的数都传进去,节省了资源,也比较简便地完成了排序。缺点是我觉得这个算法始终算不上高明,时间复杂度也仅仅在O(n),达不到问题的要求,我将在最近继续思考,争取找出更优的算法。

下面是源代码:

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    double answer = 0;
    bool ifLengthOdd = ((nums1.size() + nums2.size()) % 2 == 0) ? false : true;
            int medianPos = (nums1.size() + nums2.size()) / 2 + (ifLengthOdd ? 1 : 0);

    if (nums1.empty()) {
        if (ifLengthOdd)
            return nums2[medianPos - 1];
        else
            return (nums2[medianPos - 1] + nums2[medianPos]) / 2.0;
        }

    if (nums2.empty()) {
        if (ifLengthOdd)
            return nums1[medianPos - 1];
        else
            return (nums1[medianPos - 1] + nums1[medianPos]) / 2.0;
    }

    int pos1 = 0, pos2 = 0;
    int currentPos = 1;

/* 本层循环只找出中间那个数,长度奇偶问题循环完成后考虑 */ 
    while(1) {
        if ((nums1[pos1] <= nums2[pos2] && pos1 < nums1.size())
            || pos2 >= nums2.size()) {
            answer = nums1[pos1];
            pos1++;
        } else {
            answer = nums2[pos2];
            pos2++;
        }

        if (currentPos == medianPos)
            break;

        currentPos++;
    }

    if (!ifLengthOdd) {
        if ((nums1[pos1] <= nums2[pos2] && pos1 < nums1.size())
            || pos2 >= nums2.size())
            answer = (answer + nums1[pos1]) / 2.0;
        else
            answer = (answer + nums2[pos2]) / 2,0;
    }

    return answer;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode是一个非常受欢迎的在线编程平台,提供了大量的算法题目,涵盖了各种难度级别和题型。下面是一些常用的LeetCode算法: 1. 两数之和(Two Sum):给定一个整数数组和一个目标值,找出数组中和为目标值的两个数的索引。 2. 反转字符串(Reverse String):反转给定字符串中的字符顺序。 3. 最长公共前缀(Longest Common Prefix):找出一组字符串中最长的公共前缀。 4. 合并两个有序链表(Merge Two Sorted Lists):将两个有序链表合并为一个新的有序链表。 5. 有效的括号(Valid Parentheses):判断给定的字符串中的括号是否有效。 6. 盛最多水的容器(Container With Most Water):给定一组非负整数,表示一组垂直线在x轴上的坐标,找出两条线与x轴组成的容器可以容纳的最大水量。 7. 三数之和(3Sum):给定一个包含n个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a + b + c = 0。 8. 最长回文子串(Longest Palindromic Substring):找出给定字符串中的最长回文子串。 9. 二叉树的最大深度(Maximum Depth of Binary Tree):计算二叉树的最大深度,即从根节点到最远叶子节点的最长路径上的节点数。 10. 两个排序数组的中位数(Median of Two Sorted Arrays):给定两个大小为m和n的有序数组,找出这两个数组合并后的中位数。 以上只是LeetCode中的一小部分常用算法题目,LeetCode还有很多其他类型的题目,包括动态规划、回溯、贪心算法等等。如果你有具体的算法问题或者需要更多的题目推荐,请告诉我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值