4. 寻找两个有序数组的中位数
题目
-
中文题目
-
英文题目
分析
- 先要确定中位数是第几个数,两个数组中数一共有n个,则中位数为第 \(\frac{n+1}{2}\) (n为奇数),第 \(\frac{n+1}{2}\)和\(\frac{n+1}{2}+1\) 的平均数个(n为偶数). 所以我们先找出第 \(\frac{n+1}{2}\) 个数就很容易求出中位数了;
- 找中位数我们只需将数组分成两部分, 一侧的每一个数都比另一侧大. 且有一侧的个数刚好是\(\frac{n+1}{2}\), 中位数就在我们分割的切口处;
- 时间复杂度要求为O(log(m+n)), 所以我们在找分割处时要使用二分法;
- 分割有多钟情况, 且需要注意极限情况;
正确代码
错误代码
1. 没有使用二分法导致时间复杂度很高且超出数组边界
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int medianFirst = (nums1.length + nums2.length + 1)/2;
int aLeft = (nums1.length)/2 - 1;
int bLeft = medianFirst - aLeft - 2;
double median1;
while(true){
if(nums1[aLeft] > nums2[bLeft+1]){
aLeft--;
bLeft++;
}else if (nums2[bLeft] > nums1[aLeft+1]){
aLeft++;
bLeft--;
}else break;
}
median1 = Math.max(nums1[aLeft], nums2[bLeft]);
if((nums1.length+nums2.length)%2!=0)
return median1;
else {
return (median1 + Math.min(nums1[aLeft + 1], nums2[bLeft + 1])) / 2;
}
}
}
测试用例为[1, 3], [2]
正确代码
class Solution {
public static void main(String[] args) {
int[] nums1 = {3};
int[] nums2 = {-2, -1};
double result = findMedianSortedArrays(nums1, nums2);
System.out.println(result);
}
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
//确保第一个数组长度更短
if(nums1.length > nums2.length){
return findMedianSortedArrays(nums2, nums1);
}
int length1 = nums1.length;
int length2 = nums2.length;
int totleLength = length1 + length2;
//第一个中位数是排在第几的数
int firstMI = (totleLength + 1) / 2;
//二分法
int left = 0;
int right = length1;
int line1;
int line2;
int left1;
int right1;
int left2;
int right2;
while(true){
//第一个数组划分区域右边
line1 = (left + right)/2;
//第二个数组划分区域右边
line2 = firstMI-line1;
//检查数组越界的问题
//第一个数组的左数
left1 = line1 <=0 ? Integer.MIN_VALUE : nums1[line1-1];
//第一个数组的右数
right1 = line1 >= length1 ? Integer.MAX_VALUE : nums1[line1];
//第二个数组的左数
left2 = line2 <=0 ? Integer.MIN_VALUE : nums2[line2-1];
//第一个数组的右数
right2 = line2 >= length2 ? Integer.MAX_VALUE : nums2[line2];
if(right1 < left2){
//往右取值
left = line1+1;
}else if(left1 > right2){
//往左取值
right = line1-1;
}else{
break;
}
}
//第一个中位数
int firstM = Math.max(left1, left2);
//中位数
double m = totleLength%2 == 0 ? ( firstM+Math.min(right1, right2) )/2.0 : firstM;
return m;
}
}