要找到两个正序数组的中位数,并且满足时间复杂度为 O(log (m + n))
,我们可以使用二分查找的方法。以下是详细的解题思路和 Java 代码实现。
解题思路
-
定义问题:中位数是将两个有序数组合并后,找到中间的值。如果总长度为奇数,中位数是中间的元素;如果总长度为偶数,中位数是中间两个元素的平均值。
-
使用二分查找:
- 确保我们总是在较小的数组上进行二分查找,这样可以保证算法的高效性。
- 设定两个指针分别指向数组的开头和结尾,进行二分查找,找到一个合适的划分点
i
和j
使得:i + j = (m + n + 1) / 2
(保证左边部分包含中位数)- 左边最大值小于等于右边最小值:
nums1[i - 1] <= nums2[j]
nums2[j - 1] <= nums1[i]
-
划分逻辑:
- 如果
nums1[i - 1] > nums2[j]
,说明i
太大,需要减小i
。 - 如果
nums2[j - 1] > nums1[i]
,说明i
太小,需要增大i
。
- 如果
-
计算中位数:
- 如果总长度为奇数,中位数为左边部分的最大值。
- 如果总长度为偶数,中位数为左边最大值和右边最小值的平均值。
Java 代码实现
java
public class MedianOfTwoSortedArrays {
/**
* 寻找两个正序数组的中位数
*
* @param nums1 数组1
* @param nums2 数组2
* @return 中位数
*/
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
// 确保 nums1 是较短的数组
if (m > n) {
return findMedianSortedArrays(nums2, nums1);
}
int imin = 0, imax = m, halfLen = (m + n + 1) / 2;
while (imin <= imax) {
int i = (imin + imax) / 2; // nums1 的划分点
int j = halfLen - i; // nums2 的划分点
// 调整二分查找范围
if (i < imax && nums2[j - 1] > nums1[i]) {
imin = i + 1; // i 太小,增加 i
} else if (i > imin && nums1[i - 1] > nums2[j]) {
imax = i - 1; // i 太大,减少 i
} else { // i 正确
int maxOfLeft;
if (i == 0) {
maxOfLeft = nums2[j - 1]; // nums1 空
} else if (j == 0) {
maxOfLeft = nums1[i - 1]; // nums2 空
} else {
maxOfLeft = Math.max(nums1[i - 1], nums2[j - 1]); // 左边部分的最大值
}
if ((m + n) % 2 == 1) {
return maxOfLeft; // 奇数长度
}
int minOfRight;
if (i == m) {
minOfRight = nums2[j]; // nums1 空
} else if (j == n) {
minOfRight = nums1[i]; // nums2 空
} else {
minOfRight = Math.min(nums1[i], nums2[j]); // 右边部分的最小值
}
// 偶数长度,返回两个中位数的平均值
return (maxOfLeft + minOfRight) / 2.0;
}
}
return 0.0; // 这行理论上不会执行
}
public static void main(String[] args) {
int[] nums1 = {1, 3}; // 示例数组1
int[] nums2 = {2}; // 示例数组2
double result = findMedianSortedArrays(nums1, nums2); // 调用函数
System.out.println(result); // 输出中位数
}
}
代码说明
-
函数
findMedianSortedArrays
:- 通过二分查找确定合适的划分点
i
和j
。 - 计算并返回中位数。
- 通过二分查找确定合适的划分点
-
主方法
main
:- 提供示例数组并调用中位数计算函数,输出结果。
示例
对于输入:
nums1 = [1, 3]
nums2 = [2]
合并后的数组为 [1, 2, 3]
,中位数为 2
。
对于输入:
nums1 = [1, 2]
nums2 = [3, 4]
合并后的数组为 [1, 2, 3, 4]
,中位数为 (2 + 3) / 2 = 2.5
。
该算法有效且符合时间复杂度要求。