这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战
寻找两个正序数组的中位数
Hot100 4.寻找两个正序数组的中位数
难度:困难
给定两个大小分别为m和n的正序(从小到大)数组num1和num2。请你找出并返回这两个正序数组的中位数。
算法的时间复杂度应该为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
示例3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例5:
输入:nums1 = [2], nums2 = []
输出:2.00000
提示:
- nums1.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -10^6 <= nums1[i], nums2[i] <= 10^6
题解
法一 暴力法
这个方法不符合题目要求,但是leetcode可A。
合并两个排序数组,使用两个指针分别指向两个数组,通过比较大小的方式,将值存入新数组,若有一个数组循环结束,则将另一个数组剩下的所有值存入新数组。
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function(nums1, nums2) {
const mergeArr = [];
let i = 0, j = 0;
while(i < nums1.length && j < nums2.length){
if(nums1[i] > nums2[j]) {
mergeArr.push(nums2[j++])
}else{
mergeArr.push(nums1[i++])
}
}
while(i < nums1.length) {
mergeArr.push(nums1[i++]);
}
while(j < nums2.length) {
mergeArr.push(nums2[j++]);
}
const len = mergeArr.length;
return len % 2 === 1 ? mergeArr[Math.floor(len / 2)] : (mergeArr[len / 2] + mergeArr[len / 2 - 1]) / 2;
}
时间复杂度:O(m+n)
空间复杂度:O(m+n)
法二 二分查找
由题目得知,两个数组都是正序的,很容易就可以想出使用二分查找的方法。
本质就是直接查找出对两个数组(A、B)进行不断有条件的划分,直到满足条件:
- leftA的长度 + leftB的长度 = (两个数组长度之和 + 1)/ 2
- A左边最大(maxLeftA),A右边最小(minRightA),B左边最大(maxLeftB),B右边最小(minRightB)满足:
(maxLeftA <= minRightB && maxLeftB <= minRightA)
median就在这四个数中,再根据奇数或者偶数对数据进行处理即可。
/**
* 二分解法
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function(nums1, nums2) {
if(nums1.length > nums2.length) {
[nums1, nums2] = [nums2, nums1];
}
const m = nums1.length, n = nums2.length;
let low = 0, high = m;
while(low <= high) {
const i = low + Math.floor((high - low) / 2);
const j = Math.floor((m + n + 1) / 2) - i;
const maxLeftNums1 = i === 0 ? -Infinity : nums1[i - 1];
const minRightNums1 = i === m ? Infinity : nums1[i];
const maxLeftNums2 = j === 0 ? -Infinity : nums2[j - 1];
const minRightNums2 = j === n ? Infinity : nums2[j];
if(maxLeftNums1 <= minRightNums2 && minRightNums1 >= maxLeftNums2) {
return (m + n) % 2 === 1
? Math.max(maxLeftNums1, maxLeftNums2)
: (Math.max(maxLeftNums1, maxLeftNums2) + Math.min(minRightNums1,minRightNums2)) / 2
} else if(maxLeftNums1 > minRightNums2) {
high = i - 1;
} else {
low = low + 1;
}
}
}
时间复杂度:O(log(min(m,n)))
空间复杂度:O(log(min(m,n)))
坚持每日一练!前端小萌新一枚,希望能点个赞+在看哇~