题目链接
题目简介
给定两个大小分别为 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
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
题目解析
- 题目要求的时间复杂度为
O(Log(m + n))
,也就是指明了该算法只能使用二分查找
- 我们假设
num1
的数组长度为 m,num2
的数组长度为n
- 如果
m + n
为偶数的话,那么中位数 = (m + n)/ 2 相当于 (m + n + 1) / 2
- 如果
m + n
为奇数的话,那么中位数 = (m + n + 1)/ 2
- 如果
- 我们定义 i 和 j 分别指向我们的 num1 和 num2
i
初始值为我们num1
的中位数,j
初始值为我们num2
的中位数- 我们需要找到这样的一根假想线,且
线左边的数值
小于线右边的数值
,也相当于num1[i - 1] <= num2[j] && num2[j - 1] <= num1[i]
,满足这个条件,既可以找到我们的中位数
- 最后,我们只需要根据
m + n
的奇偶性,来得出最后的中位数即可
题目代码
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 交换下数组的值,让小一点的数组在上面
if(nums1.length > nums2.length){
int[] temp = nums1;
nums1 = nums2;
nums2 = temp;
}
int len1 = nums1.length;
int len2 = nums2.length;
// 求出两个数组的中位数
int toall = (len1 + len2 + 1) / 2;
int left = 0;
int right = len1;
while(left < right){
// 这里为什么要 right + left + 1 ?
// 如果我们写 right + left
// 假设 left = 4, right = 5
// 这种的话,i 一直等于 4,且由于 left = i ,造成无限循环
int i = (right + left + 1) / 2;
int j = toall - i;
if(nums1[i - 1] > nums2[j]){
right = i - 1;
}else{
left = i;
}
}
int i = (right + left + 1) / 2;
int j = toall - i;
// 左边的肯定要最大的 右边的要最小的
int leftNum1 = (i == 0 ? Integer.MIN_VALUE : nums1[i - 1]);
int rightNum1 = (i == len1 ? Integer.MAX_VALUE : nums1[i]);
int leftNum2 = (j == 0 ? Integer.MIN_VALUE : nums2[j - 1]);
int rightNum2 = (j == len2 ? Integer.MAX_VALUE : nums2[j]);
if((len1 + len2) % 2 == 1){
return Math.max(leftNum1, leftNum2);
}else{
return ((double)(Math.max(leftNum1, leftNum2) + Math.min(rightNum1, rightNum2))) / 2;
}
}
}