题目
解题思路
- 不能合并两个数组,合并两个数组需要每个数组进行遍历,时间复杂度是O(m+n)
中位数:将整体排序数组分为左右两个相等的序列。
例如奇数数组为1,2,3,4,5 ,此时中位数为3
例如偶数数组为1,2,3,4,5,6 ,此时中位数为(3+4)/2=3.5
分别切两个数组:保证切分后的数组结果左边最大的数 <= 右边最小的数
bash
nums1 = [1,3,5,7] -> [1,3 | 5,7]
nums2 = [2,4,6,8] -> [2,4 | 6,8]
左半部分:[1,3] + [2,4]
右半部分:[5,7] + [6,8]
- 整个数组一共有m + n 个元素。
- 左半部分元素数量固定为 (m + n + 1) / 2 【奇数长度时左边比右遍多一个,这样的到的中位数就是左边的最大值】
- 右半部分元素数量固定为 (m + n) / 2
两个数组的设定如下 ,切分时需要满足:
max(left1, left2<=min(right1, right2)nums1 左边最大值 = left1
nums1 右边最小值 = right1
nums2 左边最大值 = left2
nums2 右边最小值 = right2

代码
- 注意:
一定要让nums1是短数组 - 这样二分次数更少,复杂度O(log(min(m,n)))
- 防止 j 越界,当 nums1 比 nums2 长时,例如 nums1=2,nums2=\[\],此时计算 i=0,j=1,j!=0于是会计算nums2j - 1导致数组越界
java
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
//在较短的数组上二分
if (nums1.length > nums2.length) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.length;
int n = nums2.length;
int left_len = (m + n + 1) / 2;
int right_len = (m + n) / 2;
//初始化left和right
int i = m/2;
int j = left_len-i;
//进行分割
while(true){
int left1 = i==0?Integer.MIN_VALUE: nums1[i-1];
int left2 = j==0?Integer.MIN_VALUE: nums2[j-1];
int right1 = i==m?Integer.MAX_VALUE: nums1[i];
int right2 = j==n?Integer.MAX_VALUE: nums2[j];
//nums1左侧太大
if(left1>right2){
i--;
j++;
}
else if(left2>right1){
i++;
j--;
}
else{//分割正确
//判断是否为偶数
if((m+n)%2==0){
return (Math.max(left1,left2)+Math.min(right1,right2))/2.0;
}
else{
return Math.max(left1,left2);
}
}
}
}
- 修改成标准的二分:left,right分别表示数组1中的左右点值
- left1 > right2 时,i 向左移动 right = i-1
- left2 > right1 时,i 向右移动 left = i+1

java
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 保证 nums1 是较短数组
if (nums1.length > nums2.length) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.length;
int n = nums2.length;
int leftLen = (m + n + 1) / 2;
int left = 0;
int right = m;
while (left <= right) {
int i = left + (right - left) / 2;
int j = leftLen - i;
int left1 = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
int left2 = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
int right1 = i == m ? Integer.MAX_VALUE : nums1[i];
int right2 = j == n ? Integer.MAX_VALUE : nums2[j];
// nums1 左边太大,i 要减小
if (left1 > right2) {
right = i - 1;
}
// nums1 左边太少,i 要增大
else if (left2 > right1) {
left = i + 1;
}
// 分割正确
else {
if ((m + n) % 2 == 0) {
return (Math.max(left1, left2) + Math.min(right1, right2)) / 2.0;
} else {
return Math.max(left1, left2);
}
}
}
return 0.0;
}