题目描述
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
题目示例
示例1
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例2
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
题目分析
首先要求log级别的时间复杂度,那么肯定需要归并、二分这一类的操作。
我们假定第一个数组的长度小于第二个数组的长度,那么根据中位数的性质:将一组数据分为两组等长的数据,那么我们可以使得i为A数组分割点,j为B数组分割点,其中
A
[
0
,
i
−
1
]
.
l
e
n
+
B
[
0
,
j
−
1
]
.
l
e
n
=
A
[
i
,
A
.
l
e
n
]
.
l
e
n
+
B
[
j
,
B
.
l
e
n
]
.
l
e
n
=
(
A
.
l
e
n
+
B
.
l
e
n
)
/
2
A[0,i-1].len+B[0,j-1].len = A[i,A.len].len+B[j,B.len].len\\=(A.len+B.len)/2
A[0,i−1].len+B[0,j−1].len=A[i,A.len].len+B[j,B.len].len=(A.len+B.len)/2
那么我们就可以通过这个条件来寻找i指针的位置,那么我们该如何调整i的位置呢?
根据上图,我们需要
B
[
j
−
1
]
<
=
A
[
i
]
&
&
A
[
i
−
1
]
<
=
B
[
j
]
B[j-1]<=A[i] \& \& A[i-1]<=B[j]
B[j−1]<=A[i]&&A[i−1]<=B[j]
所以根据上式调整就好了,详情见代码分析
java代码
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
if(m>n){
int[] temp = nums1;
nums1 = nums2;
nums2 = temp;
System.out.println(nums1.length);
System.out.println(nums2.length);
int tep = m;
m = n;
n = tep;
}
// 处理一个数组为空的情况
if(m == 0){
double ans = 0.0;
if(n%2 == 0){
ans = (nums2[n/2]+nums2[n/2-1])/2.0;
}else{
ans = (nums2[n/2]);
}
return ans;
}
int iMin = 0,iMax = m-1,midLen = (m+n+1)/2;// /4+5,5+5/
while(iMin<=iMax){
System.out.println("iMin = " + iMin);
System.out.println("iMax = " + iMax);
int i = (iMax+iMin)/2;
// m<n,保证j>=0
int j = midLen-i;
// 进行指针的调整
System.out.println("i = " + i);
System.out.println("j = " + j);
if(i<iMax && nums2[j-1]>nums1[i]){
iMin = i + 1; // i偏小
}else if(i>iMin && nums1[i-1]>nums2[j]){
iMax = i - 1;// i 偏大
}else{
// i 合适
// 这时需要讨论特殊情况
int leftMax = 0;
if(i==0){
leftMax = nums2[j-1];
}else if(j==0){
leftMax = nums1[i-1];
}else{
leftMax = Math.max(nums1[i-1],nums2[j-1]);
}
int rightMin = 0;
if(i==m){
rightMin = nums2[j];
}else if(j==n){
rightMin = nums1[i];
}else{
rightMin = Math.min(nums1[i],nums2[j]);
}
if((m+n)%2 == 1){
return leftMax;
}else{
return (leftMax+rightMin)/2.0;
}
}
}
return 0.0;
}