4. 寻找两个正序数组的中位数
给定两个大小分别为 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
-106 <= nums1[i], nums2[i] <= 106
遍历合并数组
- 遍历两个数组,合并为一个有序数组
- 合并后的有序数组,根据长度奇数偶数取中值
function findMedin(arr1, arr2) {
let arr = [];
let i = 0;
let j = 0;
while (i < arr1.length || j < arr2.length) {
// arr1数组遍历完,连接上arr2剩下的数组
if (i === arr1.length) {
arr = arr.concat(arr2.slice(j)); // concat是返回一个新数组
break;
}
if(j === arr2.length) {
arr = arr.concat(arr1.slice(i));
break;
}
if (arr1[i] > arr2[j]) {
arr.push(arr2[j]);
j++;
} else {
arr.push(arr1[i]);
i++;
}
}
console.log(arr);
// 找出中位数
if (arr.length%2 === 0) {
// 偶数
let mid = arr.length / 2;
return (arr[mid] + arr[mid+1]) / 2;
} else {
// 奇数
return arr[parseInt(arr.length / 2) + 1];
}
}
console.log(findMedin([1,3,6], [2,6,8,9]));
但是先合并数组的方式时间复杂度不满足要求,题目要求时间复杂度为O(log(m+n))
- 有序数组
- 时间复杂度为O(log(m+n)) 想到了什么?二分法
例如: 数组a = [1,3,5,7,9] 数组b = [2,4,6,8,10,12,14,16]
查找两个数组的第K大的数, 数组a中的第 k/2个元素(先假设k为偶数) 数组b中的第 k/2个元素 如果a[k/2 - 1] < b[k/2 - 1],那么第k个元素不可能在a[0]~a[k/2 - 1]中,那么排除了k/2
k为奇数时 数组a中的第 parseInt(k/2)个元素 数组b中的第 k - parseInt(k/2)个元素 同上
这个up主视频讲解思路挺清楚,没看懂建议反复观看。
function findMedin(arr1, arr2) {
let len = arr1.length + arr2.length;
if (len % 2 === 0){
// 合并长度为偶数
let left = findK(arr1, 0, arr2, 0, parseInt(len/2));
let right = findK(arr1, 0, arr2, 0, parseInt(len/2) + 1);
console.log('left = ' + left + ' ;right = ' + right);
return parseFloat((left + right)/2);
} else {
// 合并长度为奇数
return findK(arr1, 0, arr2, 0, parseInt(len/2) + 1);
}
}
// 返回两个数组中第K大的元素
function findK(arr1, i, arr2, j, k){
// 处理边界情况
if (arr1.length - i > arr2.length - j) {
// 保证arr1数组长度短
return findK(arr2, j, arr1, i, k);
}
// 处理有一个空数组的情况
if (arr1.length === i) {
return arr2[j + k - 1];
}
// k === 1
if (k === 1) {
return Math.min(arr1[i], arr2[j]);
}
let idx1 = Math.min(arr1.length, i + parseInt(k/2));
let idx2 = j + k - parseInt(k/2);
if (arr1[idx1 - 1] < arr2[idx2 - 1]) {
return findK(arr1, idx1, arr2, j, k - (idx1 - i));
} else {
return findK(arr1, i, arr2, idx2, k - (idx2 - j));
}
}
// console.log(findMedin([1,3,6], [2,6,8,9]));
console.log(findMedin([1,3], [2,6,8,9]));