问题

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。找出这两个有序数组的中位数。假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]

nums2 = [2]

则中位数是 2.0

示例 2:

nums1 = [1, 2]

nums2 = [3, 4]

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

合并两个有序数组来获得中位数

1、先将两个有序数组合并为一个有序数组

2、再获取中位数

偶数情况中位数索引分别为:(m+n)/2-1,(m+n)/2。将二值求平均数。

计数情况中为数索引为:(m+n)/2

时间复杂度是O(m+n),空间复杂度是O(m+n)。

优化第一个求解方法

上一个算法是将两个有序数组合并为一个有序数组再计算中位数位置。我们可以先计算中位数位置,将两个有序数组元素逐一比较排序过程中,当索引位置到达中位数时停止。

时间复杂度是O((m+n)/2+1)=O(m+n),空间复杂度是((m+n)/2+1)=O(m+n)。

二分查找

  • 一个有序数组的中位数

长度为偶数:

数组a,索引位置初始为0,长度为m。索引 i 将有序数组划分为左右两个长度相等的部分,i = (m - 0) / 2 且必须满足如下两个条件:

1、length(a[0, i)) = length(a[i, m))

2、a[i-1] <= a[i]

则中位数是 (a[i-1] + a[i]) / 2

长度为基数:

数组a,索引位置初始为0,长度为m。索引 i 将有序数组划分为左右两个部分,其中左边部分比右边部分少一个元素,i = (m - 0) / 2 且必须满足如下两个条件:

1、length(a[0, i)) + 1 = length(a[i, m))

2、a[i-1] <= a[i]

则中位数是 a[i]

  • 两个有序数组的中位数

两个有序数组长度之和为偶数:

两个a和b有序数组的长度分别是m和n。对a数组的一个划分i和对b数组的一个划分j,使得a数组的左半部分同b数组的左半部分看作合并后有序数组c的左半部分;而a数组的右半部分同b数组的右半部分看作合并后有序数组c的右半部分。假设有i、j存在,则需满足如下条件:

1、length(a[0, i)) + length(b[0, j]) = length(a[i, m)) + length(b[j, n])

(i-0)+(j-0)=(m-i)+(n-j)

i=(m+n)/2-j

2、max(a[i-1], b[j-1]) <= min(a[i], b[j])

则中位数是 (max(a[i-1], b[j-1]) + min(a[i], b[j])) / 2

两个有序数组长度之和为基数:

两个a和b有序数组的长度分别是m和n。对a数组的一个划分i和对b数组的一个划分j,使得a数组的左半部分同b数组的左半部分看作合并后有序数组c的左半部分;而a数组的右半部分同b数组的右半部分看作合并后有序数组c的右半部分。假设有i、j存在,则需满足如下条件:

1、length(a[0, i)) + length(b[0, j]) + 1 = length(a[i, m)) + length(b[j, n])

(i-0)+(j-0)+1=(m-i)+(n-j)

i=(m+n-1)/2-j

2、max(a[i-1], b[j-1]) <= min(a[i], b[j])

则中位数是 min(a[i], b[j])

分析求解:

两个有序数组长度不管是基数还是偶数,都需要满足如上两个条件。其中第二个条件相同,而第一个条件我们可以归纳简化为i=(m+n)/2-j,因为当m+n为基数时 (m+n)/2-j = (m+n-1)/2-j。所以,只要找出数组a划分i,则可以通过公式i=(m+n)/2-j,得到数组b划分j,并且满足如下两个条件:

1、i=(m+n)/2-j

2、max(a[i-1], b[j-1]) <= min(a[i], b[j])

我们可以在数组a中,通过折半查找来取得划分i。其中IMIN为开始索引0,IMAX为数组a长度m

1)将数组a折半 i = (IMAX - IMIN) / 2

2)其中a[i-1]<=a[i],b[j-1]<=b[j]一定是成立的。

若b[j-1]>a[i]不符合条件,i只有向后移动一位变大,相应的j向前移动一位变小,才有可能符合条件b[j-1]<=a[i]。所以,此时的i并不是有效划分,有效划分在i+1~IMAX范围内。IMIN赋值为i+1,继续执行1)。

若a[i-1]>b[j]不符合条件,i只有向前移动一位变小,相应的j向后移动一位变大,才有可能符合条件a[i-1]<=b[j]。所以,此时的i并不是有效划分,有效划分在IMIN~i-1范围内。IMAX为i-1,继续执行1)。

3)最后找到合适的i和j,就可以直接计算得到中位数。

注意:

1、数组a和数组b长度的关系

必须保证0<=i<=m, 0<=j<=n;假设0<=i<=m成立,如果满足0<=j<=n,m和n之间的关系。

1)

i=(m+n)/2-j =>

j=(m+n)/2-i =>

因为i<=m,所以j=(m+n)/2-i>=(m+n)/2-m=(n-m)/2 =>

若(n-m)/2>=0,则j>=0 =>

m<=n

2)

i=(m+n)/2-j =>

j=(m+n)/2-i =>

因为i>=0,j=(m+n)/2-i<=(m+n)/2 =>

若(m+n)/2<=n,则j<=n =>

m<=n

3)

总结:当m<=n时,0<=i<=m,可以保证0<=j<=n。所以,在算法中,始终要保持数组a的长度要不大于数组b的长度。

数组a可能为空数组

2、i,j移动过程中的越界问题

1)若b[j-1]>a[i]不符合条件,i只有向后移动一位变大,相应的j向前移动一位变小,才有可能符合条件b[j-1]<=a[i]。

为保证数组不越界,j不能等于0,i不能等于m。

这两种情况要单独判断:

当j==0时,左半部分的最大值是a[i-1],右半部分的最小值是min(a[i], b[0]);

当i==m时,左半部分的最大值是max(a[m-1], b[j-1]),右半部分的最小值是b[j]。

2)若a[i-1]>b[j]不符合条件,i只有向前移动一位变小,相应的j向后移动一位变大,才有可能符合条件a[i-1]<=b[j]。所以,此时的i并不是有效划分,有效划分在0~i范围内。IMIN赋值为0,IMAX为i,继续执行1)。

为保证数组不越界,i不能等于0,j不能等于n。

这两种情况要单独判断:

当i==0时,左半部分的最大值是b[j-1],右半部分的最小值是min(a[0], b[j]);

当j==n时,左半部分的最大值是max(a[i-1], b[n-1]),右半部分的最小值是a[i]。

时间复杂度是O(log(min(m,n))),空间复杂度是O(1)。

性能分析

随机生成两个有序数组进行性能测试:

The Median is 512203030.5 by MergedSortedArrays solve(num1.length=42385384,num2.length=19210176), using time is 349 milliseconds.

The Median is 512203030.5 by OptimizingMergedSortedArrays solve(num1.length=42385384,num2.length=19210176), using time is 195 milliseconds.

The Median is 512203030.5 by Binary solve(num1.length=42385384,num2.length=19210176), using time is 0 milliseconds.

二分查找法性能最优,符合预期。

数组越界怎么判断_算法连载之求解两个有序数组的中位数相关推荐

  1. 下标要求数组或指针类型_算法一看就懂之「 数组与链表 」

    数据结构是我们软件开发中最基础的部分了,它体现着我们编程的内功.大多数人在正儿八经学习数据结构的时候估计是在大学计算机课上,而在实际项目开发中,反而感觉到用得不多. 其实也不是真的用得少,只不过我们在 ...

  2. 【Leetcode数据结构算法题】合并两个有序数组(顺序表篇)

    题目内容: 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2中的元素数目. 请你 合并 nums2 到 nums1 ...

  3. 获取字符串中的.前面的长度_算法连载之求解不含有重复字符的最长子串长度...

    问题 给定一个字符串,找出其中不含有重复字符的最长子串长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc" ...

  4. 利用分治法求两个有序数组的中位数

    也是看了一篇很好的博客,思路很清晰,只是有些地方感觉博主没有详细解释,后来理解了,做了一个小总结.原博客链接:点击打开链接 题目还是昨天的那道题目: 给定两个大小为 m 和 n 的有序数组 nums1 ...

  5. [LeetCode题解]从两个有序数组的并集中寻找第k小元素

    Given two sorted arrays A, B of size m and n respectively. Find the k-th smallest element in the uni ...

  6. 计算两个有序数组的中位数

    题目: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) 类比一个数组的中位数,求两个数组的中位数 ...

  7. JAVA实现寻找两个有序数组的中位数

    介绍 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(m + n) 你可以假设 nums1 和 nums2 不会同时 ...

  8. 判断给定的两个数是否是亲和数_动画演示LeetCode算法题:004-寻找两个有序数组的中位数...

    题目: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums1 和 nu ...

  9. 6 js 比较两个数组的差异_每天一道算法题(js)(3)——寻找两个有序数组的中位数...

    给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums1 和 nums2 ...

最新文章

  1. Anaconda系列:conda是什么?conda与pip的区别是什么?
  2. Spark 读 Elasticsearch
  3. Spark-SQL从MySQL中加载数据以及将数据写入到mysql中(Spark Shell方式,Spark SQL程序)
  4. 36岁,程序员,为公司工作8年,昨天HR说公司不准备续约
  5. SpringBoot-核心功能
  6. 必须在构造函数基/成员初始值设定项列表中初始化
  7. 实战系列-Spring Cloud微服务中三把利器Feign、Hystrix、Ribbon
  8. 5.3命名socket
  9. python类的构造方法和assert的使用,用MethodType动态绑定类方法
  10. C++模板类中使用静态成员变量(例如Singleton模式)
  11. error installing service: 拒绝访问。 (5)_CentOS7x86_64安装Tomcat8.5手册
  12. (售前)销售经理和产品经理的区别以及未来发展
  13. Django文档地址
  14. 北京-地点-文创-南锣鼓巷:南锣鼓巷
  15. 爬取图片和查询ip地址归属地
  16. java碳纤维山地车车架咋样_自行车碳纤维车架值得买吗?它有哪些优缺点?老骑手来给你答案!...
  17. 用c语言找出图片中黄颜色部分,测试:6种玫瑰颜色找出你的恋爱基因,神准!...
  18. 白胡子不杀黑胡子的真正原因
  19. 在线制作名片php,关于一个名片在线制作的问题,求高手指点阿..
  20. 【CXY】JAVA基础 之 逻辑控制

热门文章

  1. oracle简写sql,Oracle通过sqlplus编辑sql命令
  2. 中间件方法必须返回Response对象实例(tp5.1+小程序结合时候出的问题)
  3. hibernate一对多关联映射
  4. 常用模块-----configparser subprocess
  5. Tomcat无法访问中文路径的解决办法
  6. SQL 基础知识梳理1
  7. [转]使用CSS3 Grid布局实现内容优先
  8. 推荐几个图标显示控件
  9. Phpcms之核心目录phpcms
  10. 博客园T恤PP泄漏版(附图)