算法——有序数组中值
题目描述
有两个已排序数组A、B,各自大小分别为m,n。找到两个已排序数组的中值。
解题思路
将整个集合分为两个等长的子集,使一边的值总是大于另一边。这道题,可以将A、B看作一个整体,然后划分为左右两部分L和R,并且满足。
当总个数(m+n)位奇数时,结果为:
当总个数(m+n)为偶数时,结果为:
这样一来,问题简化为了寻找平分整个集合的方法,假设,使用 将数组A分为A0~Ai-1和Ai~Am-1,因此想要将集合均分,则需要,将数组B分为B0~Bj-1 和Bj~Bn-1,于是数组分为了如下两部分。
L | R |
---|---|
A[0],A[1],…,A[i-1] | A[i],A[i+1],…,A[m-1] |
B[0],B[1],…,B[j-1] | B[j],B[j+1],…,B[n-1] |
于是题目转化为,寻找合适的 ,使得,于是我们可以使用二分法来查找值,找到值后,就可以求出结果了。
代码
public static double findMedianSortedArrays (int[] a, int[] b) {
//交换数组,保证m<n
if (a.length > b.length) {
int[] temp = a;
a = b;b = temp;
}
int m = a.length, n = b.length;
int iMin = 0, iMax = m, halfLength = (m+n+1)/2;
while (iMin <= iMax) {
int i = (iMin + iMax)/2;
int j = halfLength - i;
if (i < iMax && b[j-1] > a[i]) {//当前i值较小,增加iMin到i+1处
iMin = i+1;
}else if (i > iMin && a[i-1] > b[j]) {//当前i值较大,减小iMax到i-1处
iMax = i-1;
}else {
int maxLeft = 0;
if (i == 0) {
maxLeft = b[j-1];
} else if (j == 0) {
maxLeft = a[i-1];
} else {
maxLeft = Math.max(a[i-1], b[j-1]);
}
//总个数位奇数时,返回max(L)
if ((m + n)%2==1) {
return maxLeft;
}
int minRight = 0;
if (i == m) {
minRight = b[j];
} else if (j == n) {
minRight = a[i];
} else {
minRight = Math.min(a[i], b[j]);
}
return (maxLeft+minRight)/2.0;
}
}
return 0;
}