定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 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 和 nums2:
- 令
m是nums1的长度,n是nums2的长度。 - 我们需要找到两个数组的中位数,会将这两个数组合并成一个数组,如果总长度是奇数则取中间值,如果是偶数则取中间两个值的平均。
思路
我们在想要查找的中位数位置上,定义分割线在两个数组的某个位置:
- 在
nums1中的分割位置为i,因此在nums2中的分割位置为(m + n + 1) / 2 - i。 - 这保证了左边所有的元素都是小于等于右边所有的元素。
然后我们检查以下条件:
nums1[i-1] <= nums2[j](左侧nums1的最大值小于等于右侧nums2的最小值)nums2[j-1] <= nums1[i](左侧nums2的最大值小于等于右侧nums1的最小值)
当满足以上条件时,我们可以找到中位数:
- 如果
(m + n)为偶数,中位数是(max(nums1[i-1], nums2[j-1]) + min(nums1[i], nums2[j])) / 2。 - 如果
(m + n)为奇数,中位数是max(nums1[i-1], nums2[j-1])。
JavaScript代码实现
以下是这个算法的 JavaScript 实现:
function findMedianSortedArrays(nums1, nums2) {
let m = nums1.length, n = nums2.length;
// 确保 nums1 是短的那个数组
if (m > n) {
[nums1, nums2, m, n] = [nums2, nums1, n, m];
}
let left = 0, right = m, halfLen = Math.floor((m + n + 1) / 2);
while (left <= right) {
let i = Math.floor((left + right) / 2); // nums1 的分割位置
let j = halfLen - i; // nums2 的分割位置
let maxLeft1 = (i === 0) ? -Infinity : nums1[i - 1];
let minRight1 = (i === m) ? Infinity : nums1[i];
let maxLeft2 = (j === 0) ? -Infinity : nums2[j - 1];
let minRight2 = (j === n) ? Infinity : nums2[j];
if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
// 找到了合适的分割
if ((m + n) % 2 === 0) {
return (Math.max(maxLeft1, maxLeft2) + Math.min(minRight1, minRight2)) / 2;
} else {
return Math.max(maxLeft1, maxLeft2);
}
} else if (maxLeft1 > minRight2) {
right = i - 1; // 移动分割线向左
} else {
left = i + 1; // 移动分割线向右
}
}
throw new Error("Input arrays are not sorted.");
}
// Example usage:
const nums1 = [1, 3];
const nums2 = [2];
console.log(findMedianSortedArrays(nums1, nums2)); // Output: 2.0
代码解析
- 首先,我们确保
nums1是较短的那一个数组,以便减少遍历空间。 - 然后,我们使用二分查找来找到合适的分割位置
i,并计算对应的j。 - 对于每个分割,我们检查左右两部分的条件是否满足,如果满足就可以计算中位数。
- 如果不满足,我们根据条件决定移动哪一侧的搜索范围。
- 最后返回计算的中位数。
通过这种方法,我们能在对数时间内找到中位数。