这题对我来说挺难,先用O(n)的笨办法过了,leetcode的输入集只有想不到没有做不到,所以不断加上各种边界条件代码简直就不能看了……
先附上O(n)的解法,即把两个有序数组扫一遍,归并成新的有序数组,然后取Median。
Java 版:
public class Solution {
public double findMedianSortedArrays(int A[], int B[]) {
int len = A.length + B.length;
int[] tem = new int[len];
int i = 0;
int j = 0;
int t = 0;
while(j<B.length && i<A.length){
if(A[i]>=B[j]){
tem[t] = B[j];
j++;
t++;
}else{
tem[t] = A[i];
i++;
t++;
}
}
if(i<A.length){
for(t=t;t<len;t++,i++){
tem[t] = A[i];
}
}
if(j<B.length){
for(t=t;t<len;t++,j++){
tem[t] = B[j];
}
}
if(len%2==1)
return tem[len/2];
else{
return (double)(tem[len/2]+tem[len/2-1])/2;
}
}
}
之后发现,在算法导论9.3-8有这道题,而且还尼玛是作业题……瞬间学渣都是泪……当然leetcode上不要求两数组等长,而且总长度奇偶不同,答案也会因为取中位数还是取居中两者平均值而变化,情况更复杂。
在网上找到此题的解法,千篇一律来自 leetcode之median of two sorted arrays 以及 leetcode 4 median of two sorted arrays 这两篇所讲述的算法。算法简洁巧妙,讲问题转化为求第K小(当两数组长和为奇数)或者第K小和第K+1小的平均数(当两数组长和为偶数)。源程序为C++,现将其改写为Java版。但是在Leetcode的输入集下,这种解法的耗时明显比上一种“笨办法”还要慢,虽然理论上解法二是O(log(m+n))的。
Java版:
public class Solution {
public static int findKth(int A[], int B[], int k){
if(A.length > B.length){
return findKth(B,A,k);
}
if(A.length==0){
return B[k-1];
}
if(k==1){
return Math.min(A[0], B[0]);
}
int pa = Math.min(k/2, A.length);
int pb = k - pa;
if(A[pa-1]<B[pb-1]){
return findKth(Arrays.copyOfRange(A, pa, A.length),B,k-pa );
}else if(A[pa-1]>B[pb-1]){
return findKth(A, Arrays.copyOfRange(B, pb, B.length),k-pb );
}else
return A[pa-1];
}
public double findMedianSortedArrays(int A[], int B[]) {
int len = A.length+B.length;
if(len%2==0){
return (double)(findKth(A,B,len/2)+
findKth(A,B,len/2+1))/2; // Do Not Forget (double) !
}else
return findKth(A,B,len/2+1); // Not len/2 !
}
}