关键词:二分查找 / 分割思想 / O(log(m+n))
难度评价:Hard(但理解后非常优雅)
一、题目回顾
给定两个正序数组 nums1 和 nums2,长度分别为 m、n:
nums1 = [1,3]
nums2 = [2]
合并后:
[1,2,3] → 中位数 = 2
⚠️ 关键要求
算法时间复杂度必须是
O(log (m+n))
这意味着:
- ❌ 不能直接合并数组
- ❌ 不能线性扫描
- ✅ 必须用二分查找
二、暴力思路为什么不行?
1️⃣ 合并数组 + 排序
O((m+n) log (m+n))
👉 不满足题目要求
2️⃣ 双指针合并到中位数位置
O(m+n)
👉 还是不行
三、真正的突破点:不要合并数组
💡 核心思想
我们不需要真正合并数组
只需要找到一个“分割点”,
让左右两边数量相等,并且整体有序
四、把问题转成「分割问题」
设:
- 在
nums1中切一刀:i - 在
nums2中切一刀:j
nums1: | left_A | right_A |
nums2: | left_B | right_B |
目标状态
1️⃣ 左边元素个数 = 右边元素个数(或多一个)
2️⃣ 左边所有元素 ≤ 右边所有元素
五、为什么可以用二分查找?
我们只在 较短数组 nums1 上二分:
i ∈ [0, m]
j = (m + n + 1) / 2 - i
为什么这样做?
- 搜索空间是有序的
i增大,j必然减小- 条件判断具有单调性
👉 完全符合二分查找的使用场景
六、完整代码
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 保证 nums1 是较短数组
if (nums1.length > nums2.length) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.length;
int n = nums2.length;
int left = 0, right = m;
while (left <= right) {
int i = (left + right) / 2;
int j = (m + n + 1) / 2 - i;
int A_left_max = (i == 0) ? Integer.MIN_VALUE : nums1[i - 1];
int A_right_min = (i == m) ? Integer.MAX_VALUE : nums1[i];
int B_left_max = (j == 0) ? Integer.MIN_VALUE : nums2[j - 1];
int B_right_min = (j == n) ? Integer.MAX_VALUE : nums2[j];
if (A_left_max <= B_right_min && B_left_max <= A_right_min) {
if ((m + n) % 2 == 1) {
return Math.max(A_left_max, B_left_max);
} else {
return (Math.max(A_left_max, B_left_max)
+ Math.min(A_right_min, B_right_min)) / 2.0;
}
} else if (A_left_max > B_right_min) {
right = i - 1;
} else {
left = i + 1;
}
}
return 0.0;
}
}
七、二分查找的「判定条件」才是灵魂
A_left_max <= B_right_min
&&
B_left_max <= A_right_min
这句本质是在判断:
左半部分最大值 ≤ 右半部分最小值
也就是:
max(left) ≤ min(right)
一旦成立:
- 分割完成
- 中位数就在分割线附近
八、奇偶情况统一处理的技巧
为什么用 (m + n + 1) / 2?
- 奇数时:左边多一个元素
- 偶数时:左右刚好相等
👉 一行公式统一所有情况,非常优雅
九、时间 & 空间复杂度分析
| 指标 | 复杂度 |
|---|---|
| 时间复杂度 | O(log(min(m,n))) |
| 空间复杂度 | O(1) |
这是这道题的 理论最优解。
十、这道题真正想考什么?
❌ 不是数组
❌ 不是中位数
❌ 不是数学
✅ 是你能不能把「二分查找」用在“答案空间”上
十一、总结一句话版
在较短数组上二分,
找到一个分割点,
让左右两边数量平衡且整体有序,
中位数自然浮现。
十二、写在最后
这道题是:
- 二分查找的 认知分水岭
- 从「会用模板」到「理解思想」的关键一步
如果你能把这题讲清楚,
那你对 二分查找的掌控力已经非常扎实了 💪