来自:小浩算法

01

PART

中位数

这道题是非常好的一道题目,也是前面100道里最难的题目之一,相当经典!

第4题:给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

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

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]

nums2 = [2]

则中位数是 2.0

示例 2:

nums1 = [1, 2]

nums2 = [3, 4]

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

(瞪一瞪就全部掌握)

02

PART

题目分析

中位数(Median)又称中值,统计学中的专有名词,是按顺序排列的一组数据中居于中间位置的数,代表一个样本、种群或概率分布中的一个数值,其可将数值集合划分为相等的上下两部分。对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数。

题意还是比较简单的,没有什么需要额外补充。当然可以直接暴力求解,因为都是有序数组,直接进行合并,再对合并后的数组通过判断是否是偶数个,求出中位数。但是由于这种方法肯定是达不到O(log(n))的,所以我们直接略过。如果是为了练习code能力的小伙伴,下去可以自行试试。

那如何保证时间复杂度在O(log(n))呢?这里有一个小技巧,一般如果题目要求时间复杂度在O(log(n)),大部分都是可以使用二分的思想来进行求解。当然,本题的二分是有一点反直觉的,可能不是很容易想到,一起看下。

首先,我们考虑一个问题,如果只有一个有序数组,我们需要找中位数,那肯定需要判断元素是奇数个还是偶数个,如果是奇数个那最中间的就是中位数,如果是偶数个的话,那就是最中间两个数的和除以2。

那如果是两个数组,也是一样的,我们先求出两个数组长度之和。如果为奇数,就找中间的那个数,也就是 (长度之和+1)/2 。如果为偶数,那就找 长度之和/2。比如下面的 (9+5)/2 = 7,那我们最终就是找到排列第7位的值。此时,问题其实已经转化为“找到两个数组中第k小的元素”。找到了第7位之后,第8位我们已经知道了,然后第7位和第8位的和,除以2就是我们要找的中位数(注意:这里的7和8你其实是不知道的,图中画出来,只是为了帮助理解

现在的问题是,我们如何用二分的思想来找到中间排列第7位的数。这里有一种不太好想到的方式,是用删的方式,因为如果我们可以把多余的数排除掉,最终剩下的那个数,是不是就是我们要找的数?对于上面的数组,我们可以先删掉 7/2=3 个数。那这里,可以选择删上面的,也可以选择删下面的。那这里因为 i<j,所以我们选择删除上面的3个数。

(删除前)

(删除后)

由于我们已经排除掉了 3 个数字,现在对于两个数组,我们需要找到7-3=4的数字,来进行下一步运算。我们可以继续删掉4/2=2个数。我们比较i和j的值,删除小的一边。

(删除前)

(删除后)

继续上面的步骤,我们删除 2/2=1 个数。同理,比较7和6的大小,删除小的一边。删完后是下面这样:

(7和6,删除6)

不要忘记我们的目的,我们是为了找第7小的数。此时,两个数组的第一个元素,哪个小,就是我们要找的那个数。因为7<8,所以7就是我们要找的第7小的数。

这里有一点比较特殊的,如果在删除过程中,我们要删除的K/2个数,大于其中一边的数组长度,那我们就将小的一侧数组元素都删除。比如下面这个,此时7/2=3,但是下面的数组只有2个元素,我们就将它全部删除。

删完之后,此时因为只删除了2个元素,所以k变成了5。那我们只需要返回其中一边的第5个元素就ok。

整个上面的过程,完成了本题的算法架构!

03

PART

证明过程

今天的题目有一定难度,但是并不是没办法攻克!最重要的还是三点:

  • 从整体把握整个问题的算法基础,想明白是如何从找中位数,转化成找“两个有序数组第k大的元素”

  • 能理解折半“删除”元素的过程,将问题转化为二分

  • 独立的思考+一点点的努力

根据分析,完成代码:

 1//JAVA2class Solution {3    public double findMedianSortedArrays(int[] nums1, int[] nums2) {4        int len1 = nums1.length;5        int len2 = nums2.length;6        int total = len1 + len2;7        int left = (total + 1) / 2;8        int right = (total + 2) / 2;9        return (findK(nums1, 0, nums2, 0, left) + findK(nums1, 0, nums2, 0, right)) / 2.0;
10
11    }
12
13    //找到两个数组中第k小的元素
14    public int findK(int[] nums1, int i, int[] nums2, int j, int k) {
15        if (i >= nums1.length)
16            return nums2[j + k - 1];
17        if (j >= nums2.length)
18            return nums1[i + k - 1];
19        if (k == 1) {
20            return Math.min(nums1[i], nums2[j]);
21        }
22        //计算出每次要比较的两个数的值,来决定 "删除"" 哪边的元素
23        int mid1 = (i + k / 2 - 1) < nums1.length ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
24        int mid2 = (j + k / 2 - 1) < nums2.length ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
25        //通过递归的方式,来模拟删除掉前K/2个元素
26        if (mid1 < mid2) {
27            return findK(nums1, i + k / 2, nums2, j, k - k / 2);
28        }
29        return findK(nums1, i, nums2, j + k / 2, k - k / 2);
30    }
31}

郑重申明(读我的文章必看):

  • 本系列所有教程都不会用到复杂的语言特性,不需要担心没有学过相关语法,使用啥语言纯属本人翻牌子心情。

  • 作为学术文章,虽然风格可以风趣,但严谨,我是认真的。本文所有代码均在leetcode上进行过测试运行。

  • 算法思想才是最重要的。

今天的题目可能有一定难度,建议大家自己写写画画,才能真正的做到理解和巩固。另外,我打算后面出一个二分法的系列主题,尽我之力,帮大家攻克二分类的题目。希望得到支持!(怎么支持?帮我转发就ok)

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

长按订阅更多精彩▼如有收获,点个在看,诚挚感谢

漫画:百度从Google学来的面试题,想进大厂必备!相关推荐

  1. 奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些并发编程知识是你必须要掌握的!完整学习路线!!(建议收藏)

    大家好,我是冰河~~ 今天给大家带来一篇完整的并发编程学习路线,这应该是全网最全的并发编程学习路线了吧,希望能够为各位小伙伴们带来实质性的帮助. 如果这篇文章对大家有点帮助,小伙伴们点赞,收藏,评论, ...

  2. 奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些并发编程核心技能是你必须要掌握的!!(建议收藏)

    大家好,我是冰河~~ 最近有很多学弟学妹问我:冰河,并发编程要学哪些内容呀?我看你CSDN博客的的[精通高并发系列]更新了很多高并发编程的技术文章,你是怎么学习的呢?后面你还会更新吗?啥时候更新完呀? ...

  3. 奉劝那些刚参加工作的学弟学妹们:要想进大厂,这些核心技能是你必须要掌握的!完整学习路线!!(建议收藏)

    很多小伙伴问我进大厂到底需要怎样的技术能力,经过几天的思考和总结,终于梳理出一份相对比较完整的技能清单,小伙伴们可以对照清单提前准备相关的技能,在平时的工作中注意积累和总结.只要在平时的工作中总结到位 ...

  4. 学姐的大厂面试总结,想进大厂的必看!!!

    一.明确自己的目标 1,疏理目前自己的整体能力. 2,确定自己的期望薪资. 3,明确自己更看重下一份工作的哪些点(离家近?薪资?能力成长空间?) 二.确定和筛选目标公司 1,公司规模(成立时间.人数规 ...

  5. 普通二本,学这些东西,也能进大厂

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  6. 不想进大厂的程序员是没有梦想的,2021年阿里、腾讯,java架构师指南百度云

    JVM知识 ===== 什么情况下会发生栈内存溢出. JVM的内存结构,Eden和Survivor比例. JVM内存为什么要分成新生代,老年代,持久代.新生代中为什么要分为Eden和Survivor. ...

  7. 李彦宏谈百度与Google的区别

    2014年12月下旬,郁亮带领万科80多人赴北京百度总部与百度董事长兼CEO李彦宏进行了一次深度对话,话题涉及创新激励.智能家居.职业经理人文化--以下是部分现场对话实录. 1.百度与Google的差 ...

  8. 百度计算广告学沙龙学习笔记 - 内容匹配广告

    百度计算广告学沙龙学习笔记 - 内容匹配广告 时间 2014-02-05 18:53:55 CSDN博客 原文  http://blog.csdn.net/three_body/article/det ...

  9. Google要回归国内,百度李彦宏居然不怕?我想笑

    「 事出有因 」 文末送福利 这两天关于"李彦宏回怼谷歌"的话题在朋友圈刷屏,一石激起千层浪,网友们一边倒的表态,是否说明天下民众苦百度久矣?凡事出必有因,让我们先回顾下剧情: 8 ...

最新文章

  1. 一文解决图片数据集太少的问题:详解KerasImageDataAugmentation各参数
  2. 67 Airflow配置MySQL数据库和LocalExecutor
  3. 文件上传 java web_JavaWeb 文件上传下载
  4. WhatsApp CEO向FreeBSD捐赠一百万美金
  5. Android获取手机内部存储和外部存储
  6. 提权学习之旅——Linux操作系统提权
  7. window oracle 只有bak文件怎么恢复_Oracle 11g R2 RAC数据库备份通过RMAN恢复到单实例数据库实现...
  8. Angular 动态控制 aside 标签显示和隐藏的一个例子
  9. php.ini 设置内存,php.ini怎么进行内存设置
  10. wex5 导入mysql_【分享】WeX5的正确打开方式(7)——数据组件详解
  11. 离散数学总复习精华版(最全 最简单易懂)已完结
  12. java.lang.RuntimeException
  13. Solidity节省GAS的方法
  14. 微信小程序使用formdata传参上传图片
  15. 模具设计分型的10大原则
  16. mysql+查询触发器+sql_Mysql基本查询、视图、索引、触发器
  17. 佛系计算机二级 第六弹
  18. adnroid 系统OTA升级
  19. STM32 SWD下载口无法下载的原因和解决办法
  20. 回车换行问题0x0D和0x0A

热门文章

  1. Codeforces Round #650 (Div. 3)(A-F1)题解
  2. mysql中列的增删_mysql中怎么增删一列
  3. arcgis超级工具密码_忘记电脑密码怎么办?只需要简单这样做
  4. c# 无法打开计算机.上的 服务,c# - C#Winform应用程序无法在其他计算机上运行(神秘的启动时) - 堆栈内存溢出...
  5. Find The Multiple POJ - 1426(只包含01的十进制倍数(同余模定理))
  6. P1583 魔法照片
  7. 安卓取map集合转换为json_android json解析成map格式
  8. linux显示不在sudoers文件中,Ubuntu无法使用sudo提权提示当前用户不在sudoers文件中...
  9. win下ubuntu安装mysql_MySQL在Win10与Ubuntu下的安装与配置
  10. 对delegate进行扩展 打造通用的计时完成方法