您的位置:首页 > 其它

[leetcode]Median of Two Sorted Arrays

2013-07-13 01:23 531 查看
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

1. 第一次看到此题时,我的想法是现在A中折半查找缩小范围,比如取得A的中间数A[i],然后在B中找到A[i],然后便可以缩小范围。A中没有再找B。这个与最后的推荐做法有些类似。
2. 错误或当时没想清楚的是,在B中找A[i]需要log(n)的时间,但其实不需要找A[i],直接找B[(m+n)/2 -i]作比较就行,是O[1]的时间,这样,整体就是O(log(n+m))。 此方法是在此处有描述:http://www2.myoops.org/course_material/mit/NR/rdonlyres/Electrical-Engineering-and-Computer-Science/6-046JFall-2005/30C68118-E436-4FE3-8C79-6BAFBB07D935/0/ps9sol.pdf
3. 另外的方法是:http://leetcode.com/2011/03/median-of-two-sorted-arrays.html 这篇文章提到的方法自己也承认,太复杂太难写了。其思想是先找A的中位数和B的中位数比大小,然后可得到两个数组都可舍弃一半,但舍弃的时候两个数组要舍弃同样数目的数字,这样才能继续实施算法时,新数组们的中位数是原两数组的中位数。
4. 一开始以为要对第一个和第二个中位数分别查找(n+m为偶数时),后来发现只要找到第一个中位数,第二个要么出现在同数组右边,要么在对应数组固定位置。
5. 使用推荐的做法编程时,发现是个很难写对的程序,需要考虑很多情况,同时经常有小错误。
6. 发现个小办法有点用:从最小的数组开始,然后慢慢变大。比如{1} {2,3} => {1,4} {2,3},这样能用较少的次数在纸上覆盖较多的情况。
7. 先多列出一些test case。无论面试还是写程序,都会有好处。

class Result
{
public int[] array;
public int index;
}

public class Solution {
public double findMedianSortedArrays(int A[], int B[]) {
// Start typing your Java solution below
// DO NOT write main() function

// special cases
if (A.length == 0){
if (B.length % 2 == 0)
{
return (B[B.length / 2 - 1] + B[B.length / 2]) / 2.0;
}
else
{
return B[B.length / 2];
}
}
else if (B.length == 0)
{
if (A.length % 2 == 0)
{
return (A[A.length / 2 - 1] + A[A.length / 2]) / 2.0;
}
else
{
return A[A.length / 2];
}
}
else if (A.length == 1 && B.length == 1)
{
return (A[0] + B[0]) / 2.0;
}

Result r = findMedFromFirstArray(A, B);
if (r.index == Integer.MIN_VALUE){
r = findMedFromFirstArray(B, A);
}
if (( A.length + B.length) % 2 == 0) // need to find med2
{
int med2 = findMed2(r, A, B);
return (r.array[r.index] + med2) / 2.0;
}
else
{
return r.array[r.index];
}

}

private Result findMedFromFirstArray(int A[], int B[])
{
int la = 0;
int ra = A.length - 1;
int total = 0;
if (( A.length + B.length) % 2 == 0)
{
total = (A.length + B.length)/2 - 2;
}
else
{
total = (A.length + B.length)/2 - 1;
}
while (la <= ra)
{
int mid = (la + ra) / 2;
int idx =  total - mid;

if ((idx < 0 && (idx + 1) >= 0 && A[mid] <= B[idx + 1]) ||
(idx >= 0 && idx < B.length && idx + 1 >= B.length && B[idx] <= A[mid]) ||
(idx >= 0 && idx + 1 < B.length && B[idx] <= A[mid] && A[mid] <= B[idx + 1]))
{
Result r = new Result();
r.index = mid;
r.array = A;
return r;
}
if (idx >= B.length)
{
la = mid+1;
}
else if (idx < 0)
{
ra = mid-1;
}
else if (B[idx] > A[mid])
{
la = mid + 1;
}
else
{
ra = mid - 1;
}
}
Result r = new Result();
r.index = Integer.MIN_VALUE; // this means not find
r.array = A;
return r;
}

private int findMed2(Result r, int ArrayA[], int ArrayB[])
{
int target1 = Integer.MAX_VALUE;
int target2 = Integer.MAX_VALUE;
int[] A = ArrayA;
int[] B = ArrayB;
if (r.array == B)
{
A = ArrayB;
B = ArrayA;
}
{
if (r.index + 1 < A.length)
{
target1 = A[r.index + 1];
}
int idx = ( A.length + B.length) / 2 - 2 - r.index + 1;
if (idx >= 0 && idx < B.length)
{
target2 = B[idx];
}

if (target1 < target2)
{
return target1;
}
else
{
return target2;
}
}
}

}


Discuss上有这段代码,理解一下,基本上是在A中折半猜是不是中位数,A中没有后在B中猜。最后猜到B[j]<=A[i]<=B[j+1],此时,无论奇偶(2k+1或者2k个),A[i]都是第k+1那个。那么奇数时,A[i]是正中的那个;偶数时,A[i]是中位数两个里大的那个,小的那个要从B[j]和A[i-1]里选一个。

double findMedian(int A[], int B[], int l, int r, int nA, int nB) {
if (l > r)
return findMedian(B, A, max(0, (nA+nB)/2-nA), min(nB, (nA+nB)/2), nB, nA);
int i = (l+r)/2;
int j = (nA+nB)/2 – i – 1;
if (j ≥ 0 && A[i] < B[j]) return findMedian(A, B, i+1, r, nA, nB);
else if (j < nB-1 && A[i] > B[j+1]) return findMedian(A, B, l, i-1, nA, nB);
else {
if ( (nA+nB)%2 == 1 ) return A[i];
else if (i > 0) return (A[i]+max(B[j], A[i-1]))/2.0;
else return (A[i]+B[j])/2.0;
}
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: