前言
关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!
题目描述
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
示例 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
链接:leetcode-cn.com/problems/me…
题解
- 暴力解法,将两个有序数组组合在一起,根据组合后数组的长度来计算其中位数,时间复杂度为 O(n)
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function (nums1, nums2) {
let nums = []
let i = 0
let j = 0
let k = 0
while (i < nums1.length && j < nums2.length) {
if (nums1[i] < nums2[j]) {
nums[k++] = nums1[i++]
} else {
nums[k++] = nums2[j++]
}
}
// nums1数组还有剩余元素
if (i < nums1.length) {
nums.push(...nums1.slice(i))
}
// nusm2数组还有剩余元素
if (j < nums2.length) {
nums.push(...nums2.slice(j))
}
let res
let len = nums.length
if (len % 2) {
res = nums[Math.floor(len / 2)]
} else {
res = (nums[len / 2] + nums[(len / 2) - 1]) * 0.5
}
return res
2、利用有序数组的特性来进行中位数查找,在LeetCode 数组类型题目做前必看一文中,有提到,如果题目中说到有序数组,那么应该首先想到二分搜索,这道题确实可以用二分搜索来解决,关键在于如何将其转换为二分搜索的问题。
假设我们从 nums1 数组中取前 m1 个数,从 nums2 数组中取前 m2 个数,这 m1 个数和 m2 个数共同组成了两个数组合并后的一半的数 k。
当 nums1 + nums2 的长度为偶数时,合并后的中位数为 nums1[m1-1] 和 nums[m2-1] 中的较大值 与 nums1[m1] 和 nums2[m2] 中的较小值的平均,对应着合并后 k-1 和 k 位置上的数;
当 nums1 + nums2 的长度为奇数时,合并后的中位数为 nums1[m1 - 1] 和 nums2[m2 -1] 中较大的数,对应着合并后 k-1 位置上的数。
具体可以对照着下图分析:
(备注:图来自 花花酱leetcode)
有了这个想法之后,怎么找到对应的 m1, m2 呢?
首先需要确定的一点是,m1 和 m2 只需要知道一个就可以得到另一个,因为 m1 和 m2 的个数为合并后数组的一半,而我们要找的就是在 nums1 中找到满足 nums1[m1] >= nums2[m2-1] 条件的 m1,找到 m1 之后,便可以通过判断奇偶数以及边界条件来得到合并后的中位数了。通过二分搜索加持后,此算法的时间复杂度为 O(logn)
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function (nums1, nums2) {
const n1 = nums1.length;
const n2 = nums2.length;
if (n1 > n2) {
return findMedianSortedArrays(nums2, nums1);
}
const k = Math.floor((n1 + n2 + 1) / 2); // 合并后数组一半的数
let l = 0;
let r = n1;
while (l < r) {
const m1 = Math.floor((r - l) / 2) + l;
const m2 = k - m1;
if (nums1[m1] >= nums2[m2 - 1]) {
r = m1;
} else {
l = m1 + 1;
}
}
const m1 = l;
const m2 = k - l;
// k-1 位置上的取值
const c1 = Math.max(
m1 <= 0 ? -Number.MAX_VALUE : nums1[m1 - 1],
m2 <= 0 ? -Number.MAX_VALUE : nums2[m2 - 1]
);
// 合并后的数组为奇数
if ((n1 + n2) % 2 === 1) {
return c1;
}
// k 位置上的取值
const c2 = Math.min(
m1 >= n1 ? Number.MAX_VALUE : nums1[m1],
m2 >= n2 ? Number.MAX_VALUE : nums2[m2]
);
// 合并后的数组为偶数
return (c1 + c2) / 2;
};