寻找两个正序数组的中位数
中位数:回顾一下九年义务教育知识点,就是一个数组中间的数。
偶数个:中位数就是中间两个数的平均数。
奇数个:中间的那个数。
题目:给定两个大小分别为 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.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -10^6 <= nums1[i], nums2[i] <= 10^6
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function(nums1, nums2) {
let len1 = nums1.length, len2 = nums2.length
if (len1 > len2) return findMedianSortedArrays(nums2, nums1)//对nums1和nums2中长度较小的二分
let len = len1 + len2//总长
let start = 0, end = len1 //进行二分的开始和结束位置
let partLen1, partLen2
while (start <= end) {
partLen1 = (start + end) >> 1//nums1二分的位置
partLen2 = ((len + 1) >> 1) - partLen1//nums2二分的位置
//L1:nums1二分之后左边的位置,L2,nums1二分之后右边的位置
//R1:nums2二分之后左边的位置,R2,nums2二分之后右边的位置
//如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums1二分的位置左边一个
let L1 = partLen1 === 0 ? -Infinity : nums1[partLen1 - 1]
//如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums2二分的位置左边一个
let L2 = partLen2 === 0 ? -Infinity : nums2[partLen2 - 1]
//如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
let R1 = partLen1 === len1 ? Infinity : nums1[partLen1]
//如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
let R2 = partLen2 === len2 ? Infinity : nums2[partLen2]
if (L1 > R2) {//不符合交叉小于等于 继续二分
end = partLen1 - 1
} else if (L2 > R1) {//不符合交叉小于等于 继续二分
start = partLen1 + 1
} else { // L1 <= R2 && L2 <= R1 符合交叉小于等于
return len % 2 === 0 ?
(Math.max(L1, L2) + Math.min(R1, R2)) / 2 : //长度为偶数返回作左侧较大者和右边较小者和的一半
Math.max(L1, L2) //长度为奇数返回作左侧较大者
}
}
};
分析:这道题,如果我们使用传统的方式计算,我们就是将数组合并,排序,最后找到中间的数。但是我们看要求是:时间复杂度有要求,我们一看是O(log^{(m+n)}),我们其实就是可以确定我们使用二分法来实现。
我们常规算法:
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function(nums1, nums2) {
// 合并数组
const arr =[...nums1,...nums2]
// 如果数组只有一位 直接返回该数字
if(arr.length<=1)return arr[0]
// 把数组按照正序排序
arr.sort(function(a,b){return a - b})
// 数组长度
const len = arr.length
// 判断数组长度奇还是偶
// 奇数返回
if(len%2!==0) return arr[(len-1)/2]
// 偶数处理 截取中间的俩个数字
const oArr = arr.slice(len/2-1,len/2+1)
return (oArr[0]+oArr[1])/2
};