题目:
There are two sorted arrays nums1 and nums2 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)).
意思是有两个已排好序的数组(经过检验,这里说的是升序),找出这两个数组的中位数(如果两数组数字个数的总和是奇数,则返回中间的那个数;如果个数之和是偶数,则返回中间两个数的平均数),并且题目中还限制了时间复杂度O(m+n)。
Java解题
用了两种方法,都通过了,一种很容易想到但不够优化,第二种比较好。
第一种:
假设两个数组合并为一个有序数组,计算出中位数的序号key(其实就是连个数组长度之和除以2),分别使用两个标记,或者说是指针,分别指向两个数组的第一个数字,将两个指针上的数字进行比较,较小的一方指针向后移动一个,同时,变量sum自增1,直到sum和key相等。需要注意的是:若两个数组中的其中一个若遍历完了还没有达到sum=key,则其余的只需要遍历另一个数组即可。
实现代码:
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int total=(nums1.length+nums2.length);
if(total%2!=0)
return find(nums1,nums2,(total+1)/2);
else
return (find(nums1,nums2,total/2)+find(nums1,nums2,total/2+1))/2;
}
public static double find(int[] nums1, int[] nums2,int key) {
int i=0,j=0,sum=0,flag=0;
while(sum!=key&&i<nums1.length&&j<nums2.length){
flag=0;
// System.out.println("before---key:"+key+"------i:"+i+"-------j:"+j);
if(nums1[i]<=nums2[j]){
i++;
flag=1;
}
else{
j++;
flag=2;
}
// System.out.println("after---key:"+key+"------i:"+i+"-------j:"+j);
sum++;
}
if(sum!=key){
if(i>=nums1.length)
while(sum!=key){
j++;
sum++;
flag=2;
}
if(j>=nums2.length)
while(sum!=key){
i++;
sum++;
flag=1;
}
}
if(flag==1)
return nums1[i-1];
else
return nums2[j-1];
}
第二种:
1、假设nums1数组比nums2数组元素少,key为中位数的序号,若key/2 < nums1.length 则令a=nums1[ key/2 ] b=nums2[ key/2 ]
若key/2 > nums1.length 则令a=nums1[ nums1.length ] b=nums2[ key/2 - a ]
2、如果a<b 则在nums1数组中的位于a之前的所有元素都不可能存在我们想要找的那个中位数;反之,如果b<a,则在nums2数组中的位于b之前的所有元素都不可能存在我们想要找的那个中位数,在下次循环比较的时候就不考虑这些元素了。
代码实现:
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int total=(nums1.length+nums2.length);
if(total%2!=0)
return find(nums1, 0, nums1.length, nums2, 0, nums2.length, (total+1)/2);
else
return (find(nums1, 0, nums1.length, nums2, 0, nums2.length, total/2)+find(nums1, 0, nums1.length, nums2, 0, nums2.length, total/2+1))/2;
}
public static double find(int[] nums1,int st1,int length1, int[] nums2,int st2,int length2,int key) {
// System.out.println("st1:"+st1+"------length1:"+length1+"-----st2:"+st2+"------length2:"+length2+"----key:"+key);
if(length2<length1)
return find(nums2, st2,length2, nums1, st1,length1, key);
if(length1==0)
return nums2[st2+key-1];
if(key==1)
return Math.min(nums1[st1], nums2[st2]);
int a=Math.min(length1, key/2);
int b=key-a;
if(nums1[st1+a-1]<nums2[st2+b-1]){
return find(nums1, st1+a,length1-a, nums2, st2,length2, key-a);
}
else if(nums1[st1+a-1]>nums2[st2+b-1])
return find(nums1, st1, length1, nums2, st2+b, length2-b, key-b);
else
return nums1[st1+a-1];
}
测试方法:
以上两种方法都可以用下边这个方法测试:
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = new int[]{2,4,6,8};
int[] b = new int[]{3,5,9,10,12};
System.out.println(findMedianSortedArrays(a,b));
}