news 2026/4/16 10:55:56

寻找两个正序数组的中位数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
寻找两个正序数组的中位数

class Solution {

public:

int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {

int m = nums1.size();

int n = nums2.size();

int index1 = 0, index2 = 0;

while (true) {

// 边界情况

if (index1 == m) {

return nums2[index2 + k - 1];

}

if (index2 == n) {

return nums1[index1 + k - 1];

}

if (k == 1) {

return min(nums1[index1], nums2[index2]);

}

// 正常情况

int newIndex1 = min(index1 + k / 2 - 1, m - 1);

int newIndex2 = min(index2 + k / 2 - 1, n - 1);

int pivot1 = nums1[newIndex1];

int pivot2 = nums2[newIndex2];

if (pivot1 <= pivot2) {

k -= newIndex1 - index1 + 1;

index1 = newIndex1 + 1;

}

else {

k -= newIndex2 - index2 + 1;

index2 = newIndex2 + 1;

}

}

}

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {

int totalLength = nums1.size() + nums2.size();

if (totalLength % 2 == 1) {

return getKthElement(nums1, nums2, (totalLength + 1) / 2);

}

else {

return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;

}

}

};

使用归并的方式,合并两个有序数组,得到一个大的有序数组。大的有序数组的中间位置的元素,即为中位数。

不需要合并两个有序数组,只要找到中位数的位置即可。由于两个数组的长度已知,因此中位数对应的两个数组的下标之和也是已知的。维护两个指针,初始时分别指向两个数组的下标 0 的位置,每次将指向较小值的指针后移一位(如果一个指针已经到达数组末尾,则只需要移动另一个数组的指针),直到到达中位数的位置。

假设两个有序数组的长度分别为 m 和 n,上述两种思路的复杂度如何?

第一种思路的时间复杂度是 O(m+n),空间复杂度是 O(m+n)。第二种思路虽然可以将空间复杂度降到 O(1),但是时间复杂度仍是 O(m+n)。

如何把时间复杂度降低到 O(log(m+n)) 呢?如果对时间复杂度的要求有 log,通常都需要用到二分查找,这道题也可以通过二分查找实现。

根据中位数的定义,当 m+n 是奇数时,中位数是两个有序数组中的第 (m+n)/2 个元素,当 m+n 是偶数时,中位数是两个有序数组中的第 (m+n)/2 个元素和第 (m+n)/2+1 个元素的平均值。因此,这道题可以转化成寻找两个有序数组中的第 k 小的数,其中 k 为 (m+n)/2 或 (m+n)/2+1。

假设两个有序数组分别是 A 和 B。要找到第 k 个元素,我们可以比较 A[k/2−1] 和 B[k/2−1],其中 / 表示整数除法。由于 A[k/2−1] 和 B[k/2−1] 的前面分别有 A[0..k/2−2] 和 B[0..k/2−2],即 k/2−1 个元素,对于 A[k/2−1] 和 B[k/2−1] 中的较小值,最多只会有 (k/2−1)+(k/2−1)≤k−2 个元素比它小,那么它就不能是第 k 小的数了。

因此我们可以归纳出三种情况:

如果 A[k/2−1]<B[k/2−1],则比 A[k/2−1] 小的数最多只有 A 的前 k/2−1 个数和 B 的前 k/2−1 个数,即比 A[k/2−1] 小的数最多只有 k−2 个,因此 A[k/2−1] 不可能是第 k 个数,A[0] 到 A[k/2−1] 也都不可能是第 k 个数,可以全部排除。

如果 A[k/2−1]>B[k/2−1],则可以排除 B[0] 到 B[k/2−1]。

如果 A[k/2−1]=B[k/2−1],则可以归入第一种情况处理。

可以看到,比较 A[k/2−1] 和 B[k/2−1] 之后,可以排除 k/2 个不可能是第 k 小的数,查找范围缩小了一半。同时,我们将在排除后的新数组上继续进行二分查找,并且根据我们排除数的个数,减少 k 的值,这是因为我们排除的数都不大于第 k 小的数。

有以下三种情况需要特殊处理:

如果 A[k/2−1] 或者 B[k/2−1] 越界,那么我们可以选取对应数组中的最后一个元素。在这种情况下,我们必须根据排除数的个数减少 k 的值,而不能直接将 k 减去 k/2。

如果一个数组为空,说明该数组中的所有元素都被排除,我们可以直接返回另一个数组中第 k 小的元素。

如果 k=1,我们只要返回两个数组首元素的最小值即可。

用一个例子说明上述算法。假设两个有序数组如下:

A: 1 3 4 9
B: 1 2 3 4 5 6 7 8 9
两个有序数组的长度分别是 4 和 9,长度之和是 13,中位数是两个有序数组中的第 7 个元素,因此需要找到第 k=7 个元素。

比较两个有序数组中下标为 k/2−1=2 的数,即 A[2] 和 B[2],如下面所示:

A: 1 3 4 9

B: 1 2 3 4 5 6 7 8 9

由于 A[2]>B[2],因此排除 B[0] 到 B[2],即数组 B 的下标偏移(offset)变为 3,同时更新 k 的值:k=k−k/2=4。

下一步寻找,比较两个有序数组中下标为 k/2−1=1 的数,即 A[1] 和 B[4],如下面所示,其中方括号部分表示已经被排除的数。

A: 1 3 4 9

B: [1 2 3] 4 5 6 7 8 9

由于 A[1]<B[4],因此排除 A[0] 到 A[1],即数组 A 的下标偏移变为 2,同时更新 k 的值:k=k−k/2=2。

下一步寻找,比较两个有序数组中下标为 k/2−1=0 的数,即比较 A[2] 和 B[3],如下面所示,其中方括号部分表示已经被排除的数。

A: [1 3] 4 9

B: [1 2 3] 4 5 6 7 8 9

由于 A[2]=B[3],根据之前的规则,排除 A 中的元素,因此排除 A[2],即数组 A 的下标偏移变为 3,同时更新 k 的值: k=k−k/2=1。

由于 k 的值变成 1,因此比较两个有序数组中的未排除下标范围内的第一个数,其中较小的数即为第 k 个数,由于 A[3]>B[3],因此第 k 个数是 B[3]=4。

A: [1 3 4] 9

B: [1 2 3] 4 5 6 7 8 9

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 9:20:22

如何通过Dify智能体平台集成Qwen3-14B实现自动化运营

如何通过Dify智能体平台集成Qwen3-14B实现自动化运营 在企业数字化转型的浪潮中&#xff0c;客服响应慢、运营流程重复、内容生产效率低等问题日益凸显。某电商公司曾面临这样的困境&#xff1a;每天上千条客户咨询涌入企业微信和官网&#xff0c;仅靠人工处理不仅成本高昂&…

作者头像 李华
网站建设 2026/4/11 21:56:31

MP4 转 GIF 转换器 (MP4 to GIF Converter)(源码分享)

&#x1f3a5; MP4 转 GIF 转换器 (MP4 to GIF Converter) 这是一个基于 Python 的轻量级桌面应用程序&#xff0c;旨在帮助用户将 MP4 视频文件快速转换为 GIF 动图。它提供了一个直观的图形用户界面 (GUI)&#xff0c;允许用户在转换前对视频进行裁剪、缩放和帧率调整&#…

作者头像 李华
网站建设 2026/4/15 12:28:04

公司只有功能测试,如何进一步提升自己?

一定要帮助想上进却又迷茫的人。 最近也听到一些做功能测试的同学的交流&#xff0c;天天做手工测试&#xff0c;想提升一下自己又不知道如何提升&#xff1f;其实还是在于这些同学对自己没有一个清晰的定位&#xff0c;没有明确的目标。 做为功能测试人员来讲&#xff0c;从…

作者头像 李华
网站建设 2026/4/16 0:50:01

基于Java Swing的迷宫生成与走迷宫游戏(2)

1、演示视频 基于Java Swing的迷宫生成与走迷宫游戏2、项目截图 设计说明 3.1 整体架构设计 项目采用分层设计和面向对象的思想&#xff0c;主要分为以下几个模块&#xff1a; 界面层&#xff08;UI层&#xff09;&#xff1a;负责图形界面的创建和渲染&#xff0c;包括主窗…

作者头像 李华
网站建设 2026/4/13 19:29:24

如何监控LobeChat运行状态?集成Prometheus方案探讨

如何监控LobeChat运行状态&#xff1f;集成Prometheus方案探讨 在AI助手日益渗透企业服务与个人工具的今天&#xff0c;一个稳定、可观察的对话系统前端已成为保障用户体验的核心环节。LobeChat 作为一款功能丰富、设计现代的开源聊天界面&#xff0c;凭借对多模型的支持和灵活…

作者头像 李华
网站建设 2026/4/16 0:12:55

AutoGPT与Kepler.gl集成:地理空间数据可视化自动化

AutoGPT与Kepler.gl集成&#xff1a;地理空间数据可视化自动化 在城市交通研究团队的日常工作中&#xff0c;一个常见的挑战是&#xff1a;如何快速响应“请分析深圳早高峰骑行热点”这类临时需求&#xff1f;传统流程需要手动搜索开放数据平台、下载CSV文件、用Python清洗时间…

作者头像 李华