1. 题目

2. 解答

2.1. 方法一

由于两个数组都是排好序的,因此首先可以想到的思路就是利用归并排序把两个数组合并成一个有序的长数组,然后直接取出中位数即可。

class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
""" len1 = len(nums1)
len2 = len(nums2)
nums = [] i = 0
j = 0 while (i < len1 and j < len2): if (nums1[i] <= nums2[j]):
nums.append(nums1[i])
i += 1 else:
nums.append(nums2[j])
j += 1 if (i < len1):
while(i < len1):
nums.append(nums1[i])
i += 1 if (j < len2):
while(j < len2):
nums.append(nums2[j])
j += 1 odd = (len1 + len2) % 2 # 长度是否为奇数
mid = (len1 + len2 - 1) // 2
if (odd):
return nums[mid]
else:
return (nums[mid] + nums[mid+1]) / 2

因为要遍历两个数组,所以时间复杂度为 \(O(m+n)\),而题目中要求算法的时间复杂度为 \(O(log (m+n))\),因此应该是有更高效的算法,借助于二分查找。

2.2. 方法二

所谓中位数,就是将 K 个数据分为长度相等的两组,左边的数据小于等于右边的数据。

如果我们要在任意位置 \(i\) 处将长度为 \(m\) 的数组 \(A\) 分为两部分,则共有 \(m+1\) 种分法,\(i=[0, m]\)。

\[left\_part \quad | \quad right\_part
\]

\[A[0], A[1], \cdot \cdot \cdot, A[i-1] \quad | \quad A[i], A[i+1], \cdot \cdot \cdot, A[m-1]
\]

\(i=0\) 说明左半部分没有元素,反之 \(i=m\) 说明右半部分没有元素。左半边元素个数为 \(i\) ,右半边元素个数为\(m-i\)。

同理,我们可以在任意位置 \(j\) 处将长度为 \(n\) 的数组 \(B\) 分为两部分,则共有 \(n+1\) 种分法,\(j=[0, n]\)。

\[B[0], B[1], \cdot \cdot \cdot, B[j-1] \quad | \quad B[j], B[j+1], \cdot \cdot \cdot, B[n-1]
\]

针对划分完后的数组 \(A\) 和 \(B\),如果满足:

  • 左边部分的长度等于右边部分的长度(偶数情况),\(i+j = m-i + n-j\);或者等于右边部分的长度加 1(奇数情况) ,\(i+j = m-i + n-j+1\)。

  • 左边的最大元素小于等于右边的最小元素,\(A[i-1] <= B[j] \quad and \quad B[i-1] <= A[j]\)。

那我们也就找到了中位数,\(median = \frac{max(left\_part) + min(right\_part)}{2}\)。

所以,我们要做的就是在 \(i=[0, m]\) 区间搜索一个 \(i\) 值,使得上面的条件得到满足。也即

\[A[i-1] <= B[j] \quad and \quad B[i-1] <= A[j] ,其中 \quad j = \frac{m+n+[1]}{2}-i
\]

加不加 1 取决于总的长度是奇数还是偶数,同时,为了保证 \(j\) 的范围在 \([0, n]\),我们必须要求 \(n\geqslant m\)

接下来,我们就在 \(i=[0, m]\) 区间进行二分查找。

    1. 如果满足条件,则直接返回求取中位数。
    1. 如果 \(i > 0 \quad and \quad A[i-1] > B[j]\),则减小 \(i\)。如果增加 \(i\),则 \(j\) 减小,左边序列数组 \(A\) 的值会更大,右边序列数组 \(B\) 的值会更小。
    1. 如果 \(i < m \quad and \quad B[i-1] > A[j]\),则增加 \(i\)。如果减小 \(i\),则 \(j\) 增加,左边序列数组 \(A\) 的值会更小,右边序列数组 \(B\) 的值会更大。

最后,我们求得左半部分的最大值以及右半部分的最小值,然后就可以求出中位数了。

因为,要查找的范围为 \(i=[0, m]\),而且每次查找缩小区间为原来的一半,因此时间复杂度为 \(O(log(min(m, n))\),空间复杂度为 \(O(1)\)。

class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size();
int n = nums2.size();
int len = m + n;
int odd = len % 2; int left = 0;
int i = 0, j = 0;
vector<int>::iterator A = nums1.begin();
vector<int>::iterator B = nums2.begin(); // 确保数组 A 的长度小于等于数组 B 的长度
if (m > n)
{
int temp = m;
m = n;
n = temp;
A = nums2.begin();
B = nums1.begin();
} int right = m; while(left <= right)
{
i = left + (right - left) / 2;
j = (len + odd) / 2 - i; if (i > 0 && A[i-1] > B[j])
{
right = i - 1;
}
else if(i < m && B[j-1] > A[i])
{
left = i + 1;
}
else
{
break;
}
} int left_max = 0;
int right_min = 0; // 左半部分的最大值
if (i == 0) left_max = B[j-1];
else if (j == 0) left_max = A[i-1];
else left_max = A[i-1] <= B[j-1] ? B[j-1] : A[i-1]; // 右半部分的最小值
if (i == m) right_min = B[j];
else if (j == n) right_min = A[i];
else right_min = A[i] <= B[j] ? A[i] : B[j]; if (odd)
{
return left_max;
}
else
{
return float(left_max + right_min) / 2;
}
}
};

获取更多精彩,请关注「seniusen」!

LeetCode 4——两个排序数组中的中位数的更多相关文章

  1. LeetCode:寻找旋转排序数组中的最小值【153】

    LeetCode:寻找旋转排序数组中的最小值[153] 题目描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0 ...

  2. 两个有序数组中的中位数以及求第k个最小数的值

    解法参考 <[分步详解]两个有序数组中的中位数和Top K问题> https://blog.csdn.net/hk2291976/article/details/51107778 里面求中 ...

  3. 每日一道 LeetCode (8):删除排序数组中的重复项和移除元素

    每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...

  4. leetcode 4.两个排序数组的中位数

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

  5. 【LeetCode】34. 在排序数组中查找元素的第一个和最后一个位置

    34. 在排序数组中查找元素的第一个和最后一个位置 知识点:数组,二分查找: 题目描述 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置 ...

  6. [LeetCode] 154. 寻找旋转排序数组中的最小值 II

    题目链接 : https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ 题目描述: 假设按照升序排序的数组在预 ...

  7. Java实现 LeetCode 154 寻找旋转排序数组中的最小值 II(二)

    154. 寻找旋转排序数组中的最小值 II 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找 ...

  8. Java实现 LeetCode 153 寻找旋转排序数组中的最小值

    153. 寻找旋转排序数组中的最小值 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中 ...

  9. 领扣(LeetCode)寻找旋转排序数组中的最小值 个人题解

    假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中最小的元素. 你可以假设数组中不存在重 ...

随机推荐

  1. 【字符串】跳来跳去的KMP匹配

    原理: 不给予证明啦(懒得一批 但是代码中有给还算详细的注释 参考:https://www.cnblogs.com/yjiyjige/p/3263858.html 模板题: 洛谷P3375: http ...

  2. 第10章 使用STM32CubeMX新建工程

    STM32Cube是一项意法半导体的原创活动, 通过减少开发工作.时间和成本, 使开发者的开发工作更轻松.STM32Cube 是一个全面的软件平台,包括了ST产品的每个系列.(如,STM32CubeF ...

  3. CSS3 小会

    -webkit-perspective:800px;   其子元素获得3D元素支持,这里是设置子元素距离试图的位置:若设为0 则不支持子元素获得3d效果,不支持透视. 常与transform:rota ...

  4. ContentProvider 、 ContentResolver 、 ContentObserver

    说说ContentProvider . ContentResolver . ContentObserver 之间的关系**a. ContentProvider 内容提供者,用于对外提供数据 b. Co ...

  5. js图片预览(一张图片预览)

    核心思想:无论是一张图片上传还是多图上传,首先我们都需要先获得图片对象. 栗子: <inuput type="file" id="myfile" onch ...

  6. jquery mobile 移动web(1)

    轻量级框架jQuery Mobile 所需文件 <link rel="stylesheet" href="jquery.mobile-1.1.2/jquery.mo ...

  7. 青蛙的约会(exgcd/扩展欧几里得)

    题目描述 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清 ...

  8. substr在oracle和mysql中的应用和区别

    Oracle: 书写格式: (1)Select  substr(字段名(string) , 起始位置(int) , 截取长度(int)) 示例: selectsubstr('123456',0,3)a ...

  9. Win10家庭版卸载Mysql 8.0.13实录

    因为重度嫌弃Mysql 8.0.xxx的各种妖魔鬼怪,所以想卸载了.但是,百度了很多文章,日期也是近几个月,但是却并不适用.所以特写此文记录一下. 按照百度万金油通用第一步,就是要停止MySQL的服务 ...

  10. DISTINCT 去重仍有重复的分析

    logger日志报错 插入数据时违反主键唯一约束 org.springframework.dao.DuplicateKeyException: ### Error updating database. ...