LeetCode 第4题:寻找两个正序数组的中位数
LeetCode 第4题:寻找两个正序数组的中位数
题目描述
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
算法的时间复杂度应该为 O(log (m+n))。
难度
困难
题目链接
https://leetcode.cn/problems/median-of-two-sorted-arrays/
示例
示例 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
提示
- nums1.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -106 <= nums1[i], nums2[i] <= 106
解题思路
方法一:二分查找
要达到 O(log(m+n)) 的时间复杂度,必须使用二分查找。关键是将问题转化为寻找第k小的数的问题。
关键点:
- 中位数的定义:
- 当总长度为奇数时,中位数是第 (m+n)/2 + 1 个数
- 当总长度为偶数时,中位数是第 (m+n)/2 和第 (m+n)/2 + 1 个数的平均值
- 使用二分查找来寻找第k小的数
- 每次比较两个数组的第 k/2 个数,排除掉不可能的部分
具体步骤:
- 确定中位数的位置k
- 在两个数组中进行二分查找:
- 比较两个数组中第 k/2 个数的大小
- 较小的那部分不可能包含第k小的数
- 排除较小的部分,继续查找剩余部分
- 递归进行上述过程,直到找到目标数
时间复杂度:O(log(m+n))
空间复杂度:O(1)
方法二:划分数组(更优解)
这个方法的思路是将两个数组分别划分,使得:
- 左半部分的长度等于右半部分
- 左半部分的最大值小于等于右半部分的最小值
代码实现
C# 实现(二分查找)
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
int totalLength = nums1.Length + nums2.Length;
if (totalLength % 2 == 1) {
return FindKth(nums1, 0, nums2, 0, totalLength / 2 + 1);
} else {
return (FindKth(nums1, 0, nums2, 0, totalLength / 2) +
FindKth(nums1, 0, nums2, 0, totalLength / 2 + 1)) / 2.0;
}
}
private double FindKth(int[] nums1, int start1, int[] nums2, int start2, int k) {
// 如果数组1已经用完,直接从数组2中返回第k个数
if (start1 >= nums1.Length) {
return nums2[start2 + k - 1];
}
// 如果数组2已经用完,直接从数组1中返回第k个数
if (start2 >= nums2.Length) {
return nums1[start1 + k - 1];
}
// 如果k=1,返回两个数组开头较小的数
if (k == 1) {
return Math.Min(nums1[start1], nums2[start2]);
}
// 比较两个数组中第k/2个数的大小
int mid1 = start1 + k/2 - 1 < nums1.Length ?
nums1[start1 + k/2 - 1] : int.MaxValue;
int mid2 = start2 + k/2 - 1 < nums2.Length ?
nums2[start2 + k/2 - 1] : int.MaxValue;
if (mid1 < mid2) {
// 排除nums1的前k/2个数
return FindKth(nums1, start1 + k/2, nums2, start2, k - k/2);
} else {
// 排除nums2的前k/2个数
return FindKth(nums1, start1, nums2, start2 + k/2, k - k/2);
}
}
}
代码详解
totalLength % 2 == 1:判断总长度是奇数还是偶数FindKth方法:查找第k小的数- 处理边界情况:某个数组用完或k=1
- 比较两个数组中第k/2个数的大小
- 排除较小的部分,继续递归查找
int.MaxValue:处理数组长度不足k/2的情况- 递归调用时更新起始位置和k值
执行结果
- 执行用时:92 ms
- 内存消耗:51.2 MB
总结与反思
- 这是一道经典的困难题目,考察了:
- 二分查找的应用
- 分治思想
- 边界情况的处理
- 关键点:
- 理解中位数的定义
- 正确处理奇偶长度的情况
- 高效排除不可能的部分
- 优化思路:
- 可以通过划分数组的方法进一步优化
- 注意特殊情况的处理
相关题目
- LeetCode 第215题:数组中的第K个最大元素
- LeetCode 第295题:数据流的中位数
- LeetCode 第378题:有序矩阵中第K小的元素
- LeetCode 第973题:最接近原点的K个点

浙公网安备 33010602011771号