寻寻觅觅
4.寻找两个正序数组的中位数
题目描述
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
进阶:你能设计一个时间复杂度为O(log(m+n)) 的算法解决此问题吗?
示例
输入 nums1 = [1,3], nums2 = [2] 输出: 2.00000
中位数 一般是在统计学 中描述一组数据处于中间的数值 偶数 取中间两位的平均值
合并数组排序
function findMedianSortedArrays(nums1, nums2){
let n = nums1.length
let m = nums2.length
let total = m + n
let arr = nums1.concat(nums2)
arr.sort((a,b)=>{
return a - b
})
let l = arr[(m+n)/2]
let r = arr[(m+n)/2 - 1]
if(total % 2 === 0){
return (l+ r)/2
}else{
return arr[(m+n-1)/2]
}
}
分治
思路分析
已知两个数组长度m,n total = m + n
- 奇数 我们就找 第total/ 2个的数就是中位数 total/2 不是下标
- 偶数 我们就找 第total/ 2个和第total/2 + 1个数的平均值
如何找第k个数 我就每次找两个数组的k/2 进行比较
- 谁比较小 就证明第k个不会出现在这个数组的 k/2的下标之前 就去掉这个这个数组的 k/2的元素
- k也需要减去这个 k/2
- 注意: js没有整形
我认为自己写的有问题 但leetcode 通过了 有没有路过的大佬 看一下
请看code !!!
function find(n1, i,n2,j,k){
if(n1.length - i > n2.length - j) return find(n2,j,n1,i,k)
if(i >= n1.length) return n2[j + k - 1]
if(k === 1) {
return Math.min(n1[i],n2[j])
}
let halfK = Math.floor(k/2)
let si = i + halfK
let sj = j + halfK
if(n1[si - 1] < n2[sj - 1]){
return find(n1, si, n2, j, k - halfK)
}else{
return find(n1, i, n2, sj, k - halfK)
}
}
function findMedianSortedArrays1(nums1, nums2){
let n = nums1.length
let m = nums2.length
let total = m + n
let halfTotal = Math.ceil(total/ 2)
if(total % 2 === 0){
let left = find(nums1, 0,nums2,0,halfTotal)
let right = find(nums1, 0,nums2,0,halfTotal + 1)
return (left + right) / 2
}else{
return find(nums1, 0,nums2,0,halfTotal)
}
}
console.time('result1')
let result1 = findMedianSortedArrays1([1],[2,3,5,6])
console.timeEnd('result1') // 0.133ms
console.log(result1) // 3
这个算法复杂度 为 O(logmin(m+n))
// 思路 用一条边界把两个数组划分为左右两个相等的部分 若总长度为奇数 则让左半部分多一个数
// 通过边界值去求中位数
function findMedianSortedArrays2(nums1, nums2) {
let m = nums1.length;
let n = nums2.length;
if (m > n) {
return findMedianSortedArrays2(nums2, nums1);
}
let iMin = 0;
let iMax = m;
while (iMin <= iMax) {
let i = Math.floor((iMin + iMax) / 2);
let j = Math.floor((m + n + 1) / 2) - i;
// i 和 j 满足条件的情况是 j-1 < i && j > i-1
if (j !== 0 && i !== m && nums2[j - 1] > nums1[i]) {
// 左下大于右上 代表 i需要增大 有序
iMin = i + 1;
} else if (i !== 0 && j !== n && nums1[i - 1] > nums2[j]) {
// 如果左上 大于右下
iMax = i - 1;
} else {
let maxLeft = 0;
if (i === 0) {
// i- 1 不存在 左上不存在
maxLeft = nums2[j - 1];
} else if (j === 0) {
// j - 1 不存在 左下不存在
maxLeft = nums1[i - 1];
} else {
maxLeft = Math.max(nums1[i - 1], nums2[j - 1]);
}
if(m + n % 2 !== 0) return maxLeft
let minRight = 0
if(i === m){
// 证明右上不存在
minRight = nums2[j]
}else if(j === n){
// 证明右下不存在
minRight = nums1[i]
}else {
minRight = Math.min(nums1[i],nums2[j])
}
return (minRight + maxLeft) /2
}
}
}
console.time("result2");
let result2 = findMedianSortedArrays2([1], [2, 3, 5, 6]);
console.timeEnd("result2"); // 0.133ms
console.log(result1); // 3
Baybay!!!