RT,注释都在代码中,直接上代码。
/**
* 寻找两个正序数组的中位数
* 题目描述:给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
* 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
* 你可以假设 nums1 和 nums2 不会同时为空。
*
* 示例 1:
* nums1 = [1, 3]
* nums2 = [2]
* 则中位数是 2.0
*
* 示例 2:
* nums1 = [1, 2]
* nums2 = [3, 4]
* 则中位数是 (2 + 3)/2 = 2.5
* ------------------------
* 命题关键字:二分思想、数学问题
*
* 将两个数组进行分隔,用 s1 s2 分别表示 num1 nums2 数组分隔后各自分割线左侧的元素的数量
* s1 s2 的和显然为总长度的一半【题意就相当于把整个数组拼起来然后取中位数,这时中位数左侧元素的个数就是总长度的一半】
* 在假设已知 s1 s2 应该是什么样的值的时候,如何计算中位数是显而易见的。
* 两个数组总长度为偶数时,中位数按照定义需要取中间两个元素的平均值,
* 结果为::(左侧较大的+右侧较小的值)/2
*
* 两个数组总长度为奇数时,中位数按照定义需要取正中间一个元素, s1 s2 的和为总长度的一半向下取整
* 结果为::右侧较小的值
*
*
* 但难点是,小册上 s1 s2 如何确定边界?即,分割点如何确定?
*
* 分割点 s1 s2 的可选方式是是唯一的,下面分为偶数、奇数去讨论
* 偶数的情况,如: 1 2 3 4 5 6 7 8 9 10
* s1 + s2 = 5
* 1 3 5 | 7 9
* 2 4 | 6 8 10
* 左侧取5,右侧取6
*
* s1 + s2 = 5
* 1 3 | 5 7 9
* 2 4 6 | 8 10
* 这种分隔就不行,左侧的值要统统小于右侧的值
*
*
* 奇数的情况,如: 1 2 3 4 5 6 7
* s1 + s2 = 3
* 1 | 3 5 7
* 2 4 | 6
* 这种分隔就不行,左侧的值要统统小于右侧的值
*
* s1 + s2 = 3
* 1 3 | 5 7
* 2 | 4 6
* 取右侧较小值4
*
*
* s1 + s2 = 3
* 1 3 5 7
* 2 4 6 |
* 这就不行了,右边没东西?
*
* !!!!边界的结论:左侧的最大值要小于右侧的最小值;而且分割线不能在边界上
*
*/
funMap.findMedianSortedArrays = () => {
// let nums1 = [1, 3, 5, 7, 9]
// let nums2 = [2, 4, 6, 8, 10]
let nums1 = [1, 3, 5, 7]
let nums2 = [2, 4, 6]
function findMedianSortedArrays(nums1, nums2) {
let len1 = nums1.length
let len2 = nums2.length
// 奇数
let isOdd = (len1 + len2) % 2 !== 0
let sLen = Math.floor((len1 + len2) / 2)
console.log('isOdd', isOdd)
// 这里约定 i 是用于 nums1 数组,i < len1 是防止分隔到边缘
// i 就相当于 s1,表示长度,而不是表示下标
for (let i = 1; i < sLen && i < len1; i++) {
let j = sLen - i
let leftMax = Math.max(nums1[i - 1], nums2[j - 1])
let rightMin = Math.min(nums1[i], nums2[j])
console.log('leftMax, rightMin', leftMax, rightMin)
// 边界,跳过去,试下一个分隔方式
if (leftMax > rightMin) {
continue
}
if (isOdd) {
return rightMin
} else {
return (leftMax + rightMin) / 2
}
}
}
console.log(findMedianSortedArrays(nums1, nums2))
}
funMap.findMedianSortedArrays()