欢迎来到李耶的频道【LeetCode面试题】。
寻找两个正序数组的中位数
题目
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数。
算法的时间复杂度应该为 O(log (m+n))。
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
解法一:二分查找(分割线法)
思路:在较短的数组上用二分法确定分割线位置,使得左半部分最大值 ≤ 右半部分最小值,从而在 O(log(min(m,n))) 时间内求出中位数。
javascript
function findMedianSortedArrays(nums1, nums2) {
if (nums1.length > nums2.length) {
[nums1, nums2] = [nums2, nums1];
}
const m = nums1.length;
const n = nums2.length;
let left = 0;
let right = m;
while (left <= right) {
const i = Math.floor((left + right) / 2);
const j = Math.floor((m + n + 1) / 2) - i;
const nums1Left = i === 0 ? -Infinity : nums1[i - 1];
const nums1Right = i === m ? Infinity : nums1[i];
const nums2Left = j === 0 ? -Infinity : nums2[j - 1];
const nums2Right = j === n ? Infinity : nums2[j];
if (nums1Left <= nums2Right && nums2Left <= nums1Right) {
if ((m + n) % 2 === 1) {
return Math.max(nums1Left, nums2Left);
}
return (Math.max(nums1Left, nums2Left) + Math.min(nums1Right, nums2Right)) / 2;
} else if (nums1Left > nums2Right) {
right = i - 1;
} else {
left = i + 1;
}
}
}
- 时间复杂度 / 空间复杂度:O(log(min(m,n))) / O(1)
- 优势:完全满足题目 O(log(m+n)) 的要求,是面试中的最优解
解法二:双指针归并(暴力法)
思路:用双指针将两个数组合并成一个有序数组,然后直接取中位数。虽然直观易懂,但时间复杂度不满足题目要求。
javascript
function findMedianSortedArrays(nums1, nums2) {
const merged = [];
let i = 0;
let j = 0;
while (i < nums1.length && j < nums2.length) {
if (nums1[i] < nums2[j]) {
merged.push(nums1[i++]);
} else {
merged.push(nums2[j++]);
}
}
while (i < nums1.length) merged.push(nums1[i++]);
while (j < nums2.length) merged.push(nums2[j++]);
const mid = Math.floor(merged.length / 2);
if (merged.length % 2 === 1) {
return merged[mid];
}
return (merged[mid - 1] + merged[mid]) / 2;
}
- 时间复杂度 / 空间复杂度:O(m+n) / O(m+n)
- 优势:思路简单,适合快速验证逻辑,但不满足题目复杂度要求,面试中不推荐
解法对比
| 解法 | 时间 / 空间复杂度 | 满足 O(log(m+n)) | 推荐指数 |
|---|---|---|---|
| 二分查找(分割线法) | O(log(min(m,n))) / O(1) | ✅ | ⭐⭐⭐⭐⭐ |
| 双指针归并 | O(m+n) / O(m+n) | ❌ | ⭐⭐ |
扩展题
- 数据流的中位数:设计一个支持以下两种操作的数据结构:添加一个整数,以及返回当前所有元素的中位数。
- 两个有序数组的第 K 小元素:给定两个有序数组,找出它们合并后的第 K 小的元素。
- 寻找两个正序数组的中位数(允许重复元素):如果数组中有重复元素,中位数的定义是否需要调整?
"天下难事,必作于易;天下大事,必作于细。" ------ 老子
关注李耶,每天一道面试题,一起卷起来 🔥