(给视学算法加星标,修炼编程内功)

来源:五分钟学算法

这道题目很有意思!

忽略时间复杂度的要求的话,so easy !加上了时间复杂度的要求,so hard!

而很多小伙伴一开始没有注意时间复杂度的要求,还很纳闷:这个难度是困难吗?怎么感觉比简单难度的的还简单啊。

题目来源于 LeetCode 上第 4 号问题:寻找两个有序数组的中位数。题目难度为 Hard,目前通过率为 35.6% 。

题目描述

给定两个大小为 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

题目解析

题目说的是给两个排好序的数组,让你求出这两个数组中所有元素按从小到大排列,排在中间的元素,时间复杂度也是有要求的,O(log(m + n)),m 和 n 分别是这两个数组的长度。

这里提到了时间复杂度为 O(log(m+n)) ,很容易想到的就是二分查找,所以现在要做的就是在两个排序数组中进行二分查找

具体思路如下,将问题 转化为在两个数组中找第 K 个小的数 。

求中位数,其实就是求第 k 小数的一种特殊情况。

首先在两个数组中分别找出第 k/2 大的数,再比较这两个第 k/2 大的数,这里假设两个数组为 A ,B。

那么比较结果会有下面几种情况:

  • A[k/2] = B[k/2],那么第 k 大的数就是 A[k/2]

  • A[k/2] > B[k/2],那么第 k 大的数肯定在 A[0:k/2+1] 和 B[k/2:] 中,这样就将原来的所有数的总和减少到一半了,再在这个范围里面找第 k/2 大的数即可,这样也达到了二分查找的区别了。

  • A[k/2] < B[k/2],那么第 k 大的数肯定在 B[0:k/2+1]和 A[k/2:] 中,同理在这个范围找第 k/2 大的数就可以了。

举个例子:

A = [1,3,4,7]
B = [1,2,3,4,5,6,7,8,9,10]

这两个数组总共 14 个数字,是偶数,因此要找出它们的第 15 / 2 = 7 小的数字与第 16 / 2 = 8 小的数字 。

下面以找出第 7 小的数字为例进行说明。

k = 7

k / 2 = 3

分别找出它们的第 k/2 大的数为 4 与 3 。(注意的是如果 k 是奇数,则向下取整)

根据这两个数将 A、B 数组划分为两部分。

然后对比这两个数,上边数组中的 4 和下边数组中的 3,如果哪个小,就表明该数组的前 k/2 个数字都不是第 k 小数字,可以舍弃。

舍弃掉的那三个数字肯定是在 最前面 的数字,因此一开始是要查找第 7 小的数字,现在变成了要查找第 7 - 3 = 4 小的数字。

同样的进行取两个数组的 k/2 数字进行区域划分与比较。

舍弃掉 A 数组的前部分之后,两个数组又发生了变化。

现在变成了去查找第 4 - 2 = 2 小的数字了。

此时出现了一个 特殊情况 :A 数组的 分割元素 与 B数组的 分割元素 相等,都为 4。

这种情况随意舍弃一个就行!代码编写的时候注意边界判断即可。

舍弃之后,问题简单了:查找两个数组中最小的那个数字。

只需要比较两个数组的开头数字就行了。(别忘记,这两个数组都是递增有序的)

所以第 7 小的数字是 4 。

同样的操作,可以查找出第 8 小的数字是 5。

所以,A 数组和 B 数组的中位数是 (4 + 5)÷ 2 = 4.5

如果你对上面的图片描述还是有点疑惑的话,强烈建议将下面的动画完整的看完。

动画描述

代码实现

//@author:windliang
public double findMedianSortedArrays(int[] nums1, int[] nums2) {int n = nums1.length;int m = nums2.length;int left = (n + m + 1) / 2;int right = (n + m + 2) / 2;//一个小技巧:将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k 。return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;
}private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {int len1 = end1 - start1 + 1;int len2 = end2 - start2 + 1;//让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1 if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);if (len1 == 0) return nums2[start2 + k - 1];if (k == 1) return Math.min(nums1[start1], nums2[start2]);int i = start1 + Math.min(len1, k / 2) - 1;int j = start2 + Math.min(len2, k / 2) - 1;if (nums1[i] > nums2[j]) {return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));}else {return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));}}

复杂度分析

时间复杂度:每进行一次循环,减少 k/2 个元素,所以时间复杂度是 O(log(k),而 k = (m+n) / 2,所以最终的复杂也就是 O(log(m+n)。

空间复杂度:虽然用到了递归,但是可以看到这个递归属于尾递归,所以编译器不需要不停地堆栈,所以空间复杂度为 O(1)。

References

详细通俗的思路分析,多解法

https://leetcode.wang/leetCode-4-Median-of-Two-Sorted-Arrays.html

推荐阅读

(点击标题可跳转阅读)

觉得本文有帮助?请分享给更多人

关注「视学算法」加星标,修炼编程内功

好文章,我在看❤️

这道算法题太简单?你忽略了时间复杂度的要求!相关推荐

  1. leetcode 算法题849 (简单240) 仅仅反转字母

    leetcode 算法题849 (简单240) 仅仅反转字母 题目介绍 给定一个字符串 S, 返回 "反转后的" 字符串, 其中不是字母的字符都保留在原地, 而所有字母的位置发生反 ...

  2. 2023年美赛C题 预测Wordle结果Predicting Wordle Results这题太简单了吧

    代码更新完毕啦 更新时间 2023-2-18 16:30 问题一.二建模方案.代码.数据.图片 2023-2-19 13:00 问题三.四建模方案.代码.数据.图片 ​ 相关 链接 (1)2023年美 ...

  3. python简单算法题_python - 简单算法题 - 列表偏移

    列表偏移 题目要求 lst = [1,2,3,4,5],列表向右偏移两位后,变成lst = [4,5,1,2,3] 思路分析 第一种方式:用切片将 [1,2,3] 和 [4,5] 取出来,之后合并在一 ...

  4. C语言算法题:简单密码

    一.题目 Julius Caesar 曾经使用过一种很简单的密码.对于明文中的每个字符,将它用它字母表中后 55 位对应的字符来代替,这样就得到了密文.比如字符'A'用'F'来代替.如下是密文和明文中 ...

  5. 用C语言实现津巴布韦这道算法题?

    粉丝求助: 题目内容如下: 5.津巴布韦 由于计划经济失败,津巴布韦称为世界上通胀率最高的国家.这里的物价即使在一天中也会持续上涨,所以必须实时更新物品价格.例如:1个鸡蛋的价格为35亿津巴布韦元,所 ...

  6. 算法题:输入一个表示整数的字符串,把该字符串转换成整数并输出。例如输入字符串“12345”,则输出整数“12345”

    今天这道算法题比较简单,主要考察的思考问题的全面性.这个需要考虑的几种情况. 如果输入的整数字符串是个负数,怎么处理? 如果输入的第一个字符是0,则怎么处理? 如果输入的是非0~9之间的字符怎么处理? ...

  7. LeetCode 221. Maximal Square----动态规划--谷歌面试算法题--Python解法

    题目地址:Maximal Square - LeetCode Given a 2D binary matrix filled with 0's and 1's, find the largest sq ...

  8. 一道看完答案你会觉得很沙雕的「动态规划算法题」

    这道算法题其实并不难,如果你把文章从头到尾看完的话基本上能看懂,但如果你看到最后的话大概率会说一句:这是什么沙雕题目?! 题目来源于 LeetCode 第 877 号问题:石子游戏. 为了更好理解,我 ...

  9. a*算法的时间复杂度_从经典算法题看时间复杂度

    本文首发公众号:架构精进​,排版比较清晰. 经常有同学在 LeetCode 的题解中问解法的复杂度是多少.作为一个懒人,我一直在「逃避」这个问题,毕竟这东西听起来就这么「复杂」. 但本着对题解认真负责 ...

最新文章

  1. 机器学习数据预处理之缺失值:预测填充(回归模型填充、分类模型填充)
  2. php fpm是干嘛的,php-fpm是什么?
  3. windows下的正向shell
  4. LinkedIn:用数据提高视频性能
  5. JBPM学习(一):实现一个简单的工作流例子全过程
  6. 【机器学习】决策树知识点小结
  7. 图论 —— 图的连通性 —— 并查集判断连通性
  8. python汉诺塔运行程序_用python编写一个程序,得到汉诺塔的解决方案
  9. python随机列表文本_在python中从单词列表返回随机单词
  10. winform防止sqlserver注入_ASP.NET Core 中的 依赖注入介绍
  11. js之iframe子页面与父页面通信
  12. python怎么用for循环找出最大值_从“for in”循环中获取最小值和最大值
  13. SQL Server里面如何导出包含数据的SQL脚本
  14. Cypress 增加自定义header访问
  15. php数据库输出文字怎么竖着的,关于文字竖排的详细介绍
  16. awb数据怎么计算_AWB参数概念
  17. 7-11 哥德巴赫猜想
  18. java继承关键字extends
  19. oracle oats 安装,找不到OffLine WLST課程
  20. Synopsys VCS工具介绍

热门文章

  1. 真香!精心整理了 100+Python 字符串常用操作
  2. 阿里资深算法专家:如何突围大厂算法面试?
  3. AI 重塑 IT的 5 种方式
  4. 再见 Python,Hello Julia!
  5. 这可能是Python面向对象编程的最佳实践
  6. 做人工智能必看的45篇论文 | 附下载地址
  7. 公开课 | 微信高级研究员解析深度学习在NLP中的发展和应用
  8. Microsoft HoloLens 入华一周年,都有哪些进展?
  9. 机器学习,就用Python!五大专家详解其优势何在
  10. SpringBoot 线程池,也太好用了叭!