文章目录

  • 题目
  • 一、归并算法
  • 二、二分查找法

题目

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

示例 1: 输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数2

示例 2: 输入:nums1 = [1,2], nums2 = [3,4] 输出:2.50000 解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3: 输入:nums1 = [0,0], nums2 = [0,0] 输出:0.00000

示例 4: 输入:nums1 = [], nums2 = [1] 输出:1.00000

示例 5: 输入:nums1 = [2], nums2 = [] 输出:2.00000

提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

一、归并算法

说明:第一次做这个题的时候用的是归并思想,但是归并的话时间和空间复杂度都是o(m+n),很简单,所以直接贴代码。

class Solution {private static int[] merge(int[] a, int[] b) {// TODO Auto-generated method stubint[] temp=new int[a.length+b.length];int i=0;int j=0;int k=0;while(i<a.length&&j<b.length) {temp[k++]=a[i]<b[j]?a[i++]:b[j++];}while(i<a.length) {temp[k++]=a[i++];}while(j<b.length) {temp[k++]=b[j++];}return temp;
}public double findMedianSortedArrays(int[] nums1, int[] nums2) {int[] c=merge(nums1,nums2);return c.length%2==1?c[c.length/2]:((double)c[c.length/2]+c[c.length/2-1])/2;
}
}

二、二分查找法

时间复杂度:o(log(m+n))

如何确定中位数呢?我们可以引入一个分隔线。
例如在一个数组的时候:
1)数组长度为偶数时
eg.
①长度为4的数组,分割线左边有(4+1)/2个数,中位数为分割线两边的数的平均值:(2+3)/2=2.5【说明:本应该是分割线前面有4/2,之所以(4+1)/2是为了和数组长度为奇数时形式一样,避免讨论】

②两个长度为2的数组,两数组分割线左边的数分别为:2和0,两数组分割线左边数的总数是(2+2+1)/2,中位数为分割线左边最大的数2和分割线右边最小的数的3平均值(2+3)/2=2.5
【说明:本应该是分割线位置(2+2)/2,(2+2+1)/2是为了和数组长度为奇数时形式一样,避免讨论】

分析:上面这个分割线的位置是唯一的。其要满足两个条件:
①分割线左边的数(图中分割线左边数为1、2)为两个数组的长度的一半
②分割线左边的数(上图中数为1、2)必须小于等于右边的数(上图中数为3、4)。

怎么将上面的逻辑分析转化成直观的数学表达式呢?
设数组为nums1[]、nums2[],分割线的位置在第一个数组为i,第二个数组为j。
①第一个条件很容易转化成一个数学表达式:
i+j=(m+n)/2
注:m+n为偶数,所以加1不影响整除结果,即是(m+n)/2 =(m+n+1)/2,i+j=(m+n+1)/2,之所以这样做是为了与后面的数组长度为奇数的结果相对应。
②因为nums1和nums2都是有序数组,所以在分割线左边的nums1的数肯定小于分割线右边nums1的数,同理,nums2亦然。所以,只需要如下两个数学表达式:

nums1[i-1]<nums2[j];
nums1[i]>nums2[j-1];

2)数组长度为奇数时
eg.
1.在有一个长度为3的数组时,分割线左边应该有(3+1)/2=2个数,分割线左边的第一个数则是中位数

2.下面有两个数组,长度总和为奇数(1+2=3),为了寻找中位数,我们作出了如下分割线,分割线左边有(3+1)/2=2个数,且要满足条件2(条件2见总结),很明显,分割线位置总和为2,且等于(数组总长度+1)/2即是(3+1)/2。


分析知道和1中奇数情况一模一样,所以总结出:
设数组为nums1[]、nums2[],分割线的位置在第一个数组为i,第二个数组为j。
i+j=(m+n+1)/2; nums1[i-1]<nums2[j]; nums1[i]>nums2[j-1];

那么我们如何用二分查找来寻找中位数呢?
i+j=(m+n+1)/2;知道,我们只需要确定在一个数组中的位置i,就可以找到另一个数组中的位置j。为了解决数组越界,我们选择在数组长度比较小的那个数组上进行二分查找。那么,当什么位置查找成功呢?这个位置是唯一的吗?根据中位数的性质,非常容易可以推断出这个分割线的位置是唯一的。那么,我们在查找到这个位置的时候如何停止呢?我们引入左右分割线左右边界(left=0,right=nums1.length,如下图),然后利用nums1[i-1]<nums2[j]; nums1[i]>nums2[j-1];逐步缩小搜索区间(具体思路在文末有详细描述),最终左右边界相等时搜索停止,即当left=right时搜索停止且left即为nums1中分割线i的位置。

class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {int m=nums1.length;int n=nums2.length;if((m+n)==1)return m==1?nums1[0]:nums2[0];int left=0;int right=m;if(m>n){right=n;int[] temp=nums1;//注意这种写法nums1=nums2;nums2=temp;}int total=(m+n+1)/2;while(left<right) {int i=left+(right-left)/2;int j=total-i;if(nums1[i]>nums2[j-1]) {//搜索区间[left,i],要注意区间只有两个数时是否会无限循环right=i;}else {//搜索区间[i+1,right],要注意区间只有2个数是否会无限循环left=i+1;}}    int i=left;int j=total-i;int lvalue,rvalue;if(i-1<0) {lvalue=nums2[j-1];}else if(j-1<0) {lvalue=nums1[i-1];}else lvalue=nums1[i-1]>nums2[j-1]?nums1[i-1]:nums2[j-1];if(i>=nums1.length) {rvalue=nums2[j];}else if(j>=nums2.length) {rvalue=nums1[i];}else rvalue=nums1[i]<nums2[j]?nums1[i]:nums2[j];return (m+n)%2==0?((double)(lvalue+rvalue)/2):lvalue;
}
}

值得强调的是:
if(nums1[i]>nums2[j-1]) {
//搜索区间[left,i]
right=i;
}
else {
//搜索区间[i+1,right]
left=i+1;
}
我们很容易理解,当nums1[i]<=nums2[j-1]时,分割线的搜索区间应该是[i+1,right],为什么在else的时候分割线的搜索区间一定是[left,i]呢?

我们用A1、A2模拟分割线左右两边nums1的数据,B1、B2为分割线左右两边nums2的数据,因为我们只能找到一条在符合i+j=(m+n+1)/2的同时,符合A1<B2,B1<A2的分割线,而且,如果nums1中分割线左移(由i+j=(m+n+1)/2可知nums2中分割线右移),A1、A2减小,B1、B2增大。我们在来回顾之前的问题,A1>B2时,分割线的搜索区间应该在哪里呢?很明显,为了使B1>A2,分割线应该尽量左移,直到符合条件的最左端,因为越左,B1就会增大,A2就会减小,就会趋近A1>B2的条件。

【注意】
1.在数组的有关问题中,一定要注意越界问题,在分割搜索区间的有关算法中,一定要注意栈溢出问题(也就是无限循环)。
2.代码还未进行优化,参考了leetcode的标准答案,发现可以用一些函数解决长串的if else逻辑判断,代码具有更好的可读性。有时间我会把优化后的代码补充的文章的末尾。

优化后:

class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {int m=nums1.length;int n=nums2.length;if((m+n)==1)return m==1?nums1[0]:nums2[0];int left=0;int right=m;if(m>n){right=n;int[] temp=nums1;//注意这种写法nums1=nums2;nums2=temp;}int total=(m+n+1)/2;while(left<right) {int i=left+(right-left)/2;int j=total-i;if(nums1[i]>nums2[j-1]) {right=i;}else {left=i+1;}}    int i=left;int j=total-i;int nums1LValue=i-1>=0?nums1[i-1]:Integer.MIN_VALUE;int nums2LValue=j-1>=0?nums2[j-1]:Integer.MIN_VALUE;int nums1RValue=i>=nums1.length?Integer.MAX_VALUE:nums1[i];int nums2Rvalue=j>=nums2.length?Integer.MAX_VALUE:nums2[j];return (m+n)%2==0?(double)(Math.min(nums1RValue, nums2Rvalue)+Math.max(nums1LValue, nums2LValue))/2:Math.max(nums1LValue, nums2LValue);
}
}

Leetcode04--给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。相关推荐

  1. LeetCode3:合并两个有序数组 给你两个有序数数组,nums1和nums2,请你将nums2合并到nums1中,使nums1成为一个有序数组.

    合并两个有序数组 问题描述: 给你两个有序数数组,nums1和nums2,请你将nums2合并到nums1中,使nums1成为一个有序数组. 说明: 初始化nums1和nums2的元素数量分别为m和n ...

  2. Leetcode4-寻找两个正序数组的中位数原理及代码实现

    LeetCode4 hard 题目 寻找两个正序数组的中位数 给定两个大小为m和n的正序(从小到大)数组nums1和nums2.请你找出这两个正序数组的中位数,并且要求算法时间复杂度为O(log(m+ ...

  3. 二分法分页 mysql_LeetCode 04寻找两个正序数组的中位数(困难)二分法

    呕心沥血的一个题解,点赞关注在看,一键三联,一起加入我们打卡!. 题目描述:呕心沥血的一个题解,点赞关注收藏,一键三联,一起加入我们打卡! 题目描述:给定两个大小为 m 和 n 的正序(从小到大)数组 ...

  4. java打乱一组正序数字,Leetcode︱4.Median of Two Sorted Arrays寻找两个正序数组的中位数.java...

    题目 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2.请你找出并返回这两个正序数组的 中位数 . 示例 : 输入:nums1 = [1,3], nums2 = [2 ...

  5. LeetCode - 4. 寻找两个正序数组的中位数

    题目来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays 题目描述 给定两个大小为 m 和 n ...

  6. [二分搜索|快速选择] leetcode 4 寻找两个正序数组的中位数

    [二分搜索|快速选择] leetcode 4 寻找两个正序数组的中位数 1.题目 题目链接 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2.请你找出并返回这两个正序数组 ...

  7. 2022-6-13 全O(1)的数据结构,两数相加,无重复字符的最长子串,寻找两个正序数组的中位数,盛最多水的容器,......

    1. 全 O(1) 的数据结构 Design a data structure to store the strings' count with the ability to return the s ...

  8. 寻找两个正序数组的中位数Python解法

    给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2.请你找出并返回这两个正序数组的 中位数 . 算法的时间复杂度应该为 O(log (m+n)) . 例: 输入:num ...

  9. 寻找两个正序数组的中位数——冒泡排序(归并排序)

    给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2.请你找出并返回这两个正序数组的 中位数 . 冒泡算法 class Solution {public double f ...

最新文章

  1. 雷克世界:Gyrfalcon加入芯片角斗场,又一款改变AI界的产品问世
  2. 清除XCode缓存和生成文件
  3. python3精要(50)-类
  4. Java I/O体系原理
  5. python selenium 判断元素是否可见
  6. 基础编程题目集 7-3 逆序的三位数 (10 分)
  7. noip2019集训测试赛(二)
  8. 无法登陆skype显示无法找到服务器,无法登录 Lync,因为找不到此登录地址 - Skype for Business | Microsoft Docs...
  9. 苹果摆脱对中国制造的依赖?iPhone14的拆解结果显示恰恰相反,更离不开中国制造了...
  10. 目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危重病人的病情变化,还会延误抢救时机。某医院打算开发一个以计算机为中心的患者监护系统,请用数据流图描述下面系统的业务流程。
  11. C++ operator重载运算符详解
  12. python里使用协程和StreamReader、StreamWriter来创建echo服务端
  13. html play控件,HTML DOM Audio play()用法及代码示例
  14. 私域流量变现有哪些方式?
  15. 【互联网广告】移动互联网广告
  16. 毕业设计 单片机智能录音器设计与实现 - 物联网 嵌入式
  17. 如何使用OpenCV在图像中抠出指定的颜色区域
  18. 世界上最神奇的数字是: 142857
  19. 微阵列数据特征选择的模因算法
  20. 把复杂的事物及逻辑尽量简单化

热门文章

  1. Java核心(集合类1-概述、Collection 接口 、List 集合)
  2. 2022-2028全球踏步机测力计行业调研及趋势分析报告
  3. 程序员效率:整理常用的在线笔记软件
  4. python plc fx5u_三菱PLC FX5U系列模块型号对照一览表
  5. 蓝牙耳机厂家新品发布——ANC主动降噪耳机U2065
  6. 将10件商品的英文名称存储在数组中,输出名称的第3个字符是‘b‘的所有商品英文名称;再输出名称的长度小于6个字符的商品英文名称。
  7. iOS录屏直播(一)初识ReplayKit
  8. matlab 狄利克雷函数代码,狄利克雷函数
  9. 微信后台 phxrpc (v0.8) 之 Timer(二)
  10. web项目上云_联想Filez携手浙江中烟,发力“云”端,打造“烟草上云”新势能...