题解
划分元素组
长数组a,短数组b
数组 | 元素组1 | 元素组2 |
---|---|---|
a(长度为m) | a1,a2,a3...ai | ai+1,ai+2...am-1,am |
b(长度为n) | b1,b2,b3...bj | bj+1,bj+2...bn-1,bn |
划分保证元素组1中元素一定小于等于元素组2中的元素,且size(元素组1)-size(元素组2)的绝对值最小。
- 若m+n为偶数,划分之后size(元素组1)==size(元素组2)。则中位数一定是ai,ai+1,bj,bj+1这四个数中两个数的平均数。
- 若m+n为奇数,划分之后size(元素组1)+1==size(元素组2)。则中位数一定是ai,ai+1,bj,bj+1这四个数中的一个。
如何划分数组
- 划分长数组,因为长数组中的元素能定位短数组中的不同元素(也可能定位不到),而短数组定位长数组中的元素是受限的。
- 根据长数组元素定位短数组元素。
考虑如下情况。
短数组a = {3};
长数组b = {1,2,4,5,6};
若用短数组去定位长数组,则a0总是定位到b3(下标=(m+n)/2-0=3,采用不同的计算方法可以得到不同的下标),而b3=5,显然不是中位数。
确定中位数的值
- 若m+n为偶数,则ans = (max(ai,bj)+min(ai+1,bj+1))/2;
- 若m+n为奇数,由于元素组2比元素组1个数多一个,中位数一定存在于ai+1,bj+1,则ans = min(ai+1,bj+1);
Code
class Solution {
public:
double findMedianSortedArrays(vector<int>& a, vector<int>& b) {
// m,n表示两vector数组的大小。
int m = a.size();
int n = b.size();
// 若a数组长度小于b数组,则交换两数组。因为我们要根据长数组元素定位短数组中的对应元素
if(m < n) return findMedianSortedArrays(b,a);
int l = 0, r = m;
double ans;
int mid1, mid2,left1,left2,right1,right2;
while (l < r) {
// mid1为二分数组a,mid2对应mid1取值
mid1 = (l + r) / 2;
mid2 = (m + n) / 2 - mid1;
// 如果mid2越界,调整l和r,重新确定mid1。
if(mid2 < 0){
r = mid1;
continue;
}
if(mid2 > n){
l = mid1+1;
continue;
}
// 取出a[i]、a[i+1]、b[j]、b[j+1]。左边越界,设为最小值;右边越界,设为最大值。
left1 = mid1 - 1 <= -1 ? INT_MIN : a[mid1 - 1];
right1 = mid1 >= m ? INT_MAX : a[mid1];
left2 = mid2 - 1 <= -1 ? INT_MIN : b[mid2 - 1];
right2 = mid2 >= n ? INT_MAX : b[mid2];
// 如果满足左边元素组小于等于右边元素组,跳出循环
if (right1 >= left2 && left1 <= right2) {
break;
}
// 如果不满足,则调整l,r重新取mid1。
if (right1 < left2) {
l = mid1+1;
}
if (left1 > right2) {
r = mid1;
}
}
//如果为奇数
if (1 & (m + n)) {
ans = 1.0*min(right1, right2);
}
else {
ans = 1.0*(max(left1, left2) + min(right1, right2)) / 2;
}
return ans;
}
};