LeetCode 4.寻找两个正序数组的中位数
题目描述
给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。
请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应为 O(log (m+n))
。
示例 1:
输入:
nums1 = [1, 3],nums2 = [2]
输出: 2.0
示例 2:
输入:
nums1 = [1, 2],nums2 = [3, 4]
输出: 2.5
Java 实现代码
java
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if (nums1.length > nums2.length) {
return findMedianSortedArrays(nums2, nums1); // 确保nums1较短
}
int m = nums1.length;
int n = nums2.length;
int left = 0, right = m;
int maxLeft = 0, minRight = 0;
while (left <= right) {
int i = left + (right - left) / 2;
int j = (m + n + 1) / 2 - i;
int nums1LeftMax = (i == 0) ? Integer.MIN_VALUE : nums1[i - 1];
int nums1RightMin = (i == m) ? Integer.MAX_VALUE : nums1[i];
int nums2LeftMax = (j == 0) ? Integer.MIN_VALUE : nums2[j - 1];
int nums2RightMin = (j == n) ? Integer.MAX_VALUE : nums2[j];
if (nums1LeftMax <= nums2RightMin && nums2LeftMax <= nums1RightMin) {
maxLeft = Math.max(nums1LeftMax, nums2LeftMax);
minRight = Math.min(nums1RightMin, nums2RightMin);
break;
} else if (nums1LeftMax > nums2RightMin) {
right = i - 1;
} else {
left = i + 1;
}
}
if ((m + n) % 2 == 1) {
return maxLeft;
} else {
return (maxLeft + minRight) / 2.0;
}
}
}
解题思路
二分查找法
为了满足时间复杂度要求
O(log (m+n))
,可以使用二分查找法:
- 我们将较短的数组设为
nums1
,较长的数组设为nums2
。总是假设m <= n
。- 在
nums1
上进行二分查找,将数组分割成两个部分,使得左边部分的元素总数等于右边部分。- 使用二分查找不断调整分割点,直到找到正确的分割,使得左半部分的最大值 ≤ 右半部分的最小值。
设分割点为
i
和j
,满足以下条件:
nums1[i-1] <= nums2[j]
nums2[j-1] <= nums1[i]
中位数计算
- 如果总长度是奇数,中位数为
max(nums1[i-1], nums2[j-1])
。- 如果总长度是偶数,中位数为
(max(nums1[i-1], nums2[j-1]) + min(nums1[i], nums2[j])) / 2
。
复杂度分析
- 时间复杂度:O(log(min(m, n))),其中 m 和 n 分别是两个数组的长度。这是因为我们在较小的数组上进行二分查找。
- 空间复杂度:O(1)。我们只使用了常量级别的额外空间。
执行过程示例
示例 1:
nums1 = [1, 3], nums2 = [2]
初始化 :
m = 2, n = 1
,left = 0, right = 2
交换数组使得nums1
是较短数组。第一次迭代:
i = 1
,j = 1
nums1[i-1] = 1
,nums1[i] = 3
nums2[j-1] = 2
满足nums1[i-1] <= nums2[j]
,nums2[j-1] <= nums1[i]
。计算中位数:
- 奇数总数,
max(1, 2) = 2
,返回2.0
。
示例 2:
nums1 = [1, 2], nums2 = [3, 4]
初始化 :
m = 2, n = 2
,left = 0, right = 2
。无需交换数组。第一次迭代:
i = 1
,j = 1
nums1[i-1] = 1
,nums1[i] = 2
nums2[j-1] = 3
,nums2[j] = 4
条件不满足,调整left = i + 1 = 2
。第二次迭代:
i = 2
,j = 0
nums1[i-1] = 2
nums2[j] = 3
满足条件。计算中位数:
- 偶数总数,
(max(2, 1) + min(3, 4)) / 2 = (2 + 3) / 2 = 2.5
。