問題:設X[0:n-1]和Y[0:n-1]為兩個數組,每個數組中含有n個已排好序的數。試設計一個O(logn)時間的分治算法,找出X和Y的2n個數的中位數
思想:
對於數組X[0:n-1]和Y[0:n-1]先分別找出X和Y的中位數xa和yb。求中位數的算法是這樣的,若n是奇數,即數組X和Y中各有奇數個數字,因為X和Y已經排好序了,所以去數組下標為(n-1)/2處的數即為中位數。若n是偶數,則取(n-1)/2向下取整和向上取整這兩個位置的數的平均值作為中位數。
兩者進行比較,
(1)若xa=yb則xa或者xb即為整個2n個數中的中位數,算法結束。因為:若每個數組中數字的個數是偶數個,則X中小於中位數的有n/2個,大於中位數的有n/2個,同理Y也是如此,所以在整個2n數組中比xa=yb小的共有n個數,比n大的共有n個數,即為中位數。若每個數組中數字的個數是奇數,則X中小於xa的有(n-1)/2個,大於xa的也有(n-1)/2個,同理Y中也是如此,所以對於xa或者是yb則整個2n數組中小於和大於他們的數分別為(n-1)個,取這兩個數的平均值(xa+yb)/2=xa=yb即為中位數.
(2) 若xa>yb,則說明整個2n個數的的中位數一定在X數組的前一半和Y數組的后一半中,因為:若中位數在X數組的中位數之后,則比它小的數共有X數組中大於n/2個數以及Y數組中大於n/2個數總計超過了n個數,不符合中位數的定義。若中位數是在Y數組的前一半之中,則比它大的數字共有Y中包括中位數在內的后半部數加上X數組包括中位數在內的后半部,這樣也超過了n個數,不符合中位數的定義。
(3) 若xa<yb,則同上理由,整個2n的數的中位數應該在X數組的后一半和Y數組的前一半中。
確定中位數所在的數組范圍后,遞歸調用求中位數算法對這個范圍的數組求中位數重復上述過程,直至:
1.出現xa=yb情況,找到了中位數算法結束。
2.數組分割至左右兩部數組只有一個數字的情況,求其平均值即為中位數
代碼:
1 /* 2 思路:求兩有序數組x和y的第k個數,思路如下: 3 若k為1,則返回兩數組的最小值 4 取x的第i個數x0,取y的第(k-i)個數y0 5 若x0=y0,則x0即為所求 6 若x0<y0,則丟棄x的前i個數,k=k-i,遞歸 7 若x0>y0,則丟棄y的前(k-i)個數,k=i,遞歸 8 */ 9 import java.util.Scanner; 10 import java.util.List; 11 import java.util.ArrayList; 12 13 public class Solution{ 14 16 public int findOneSideMedian(int a[]){ 17 int mid; 18 int length=a.length; 19 //if(a[])數組長度a.length 20 if((length&0x01)==0){//判斷子數組的長度是奇數還是偶數 21 mid=(a[length/2]+a[length/2-1])/2; 22 }else{ 23 mid=a[length/2]; 24 } 25 return mid; 26 } 27 28 public double findMedian(int x[],int y[] int n){ 29 if(n==0){ 30 break; 31 } 32 int mid_x=findOneSideMedian(x); 33 int mid_y=findOneSideMedian(y); 34 if(n==1){ 35 return (mid_x+mid_y)/2; 36 } 37 if(mid_x==mid_y){ 38 return mid_x; 39 }else if(mid_x>mid_y){ 40 int[] x2=Arrays.copyOfRange(x,0,n/2); 41 int[] y2=Arrays.copyOfRange(y,Math.ceil(n/2),n); 42 n=n/2; 43 findMedian(x2,y2,n); 44 }else if(mid_x<mid_y){ 45 int[] x2=Arrays.copyOfRange(x,Math.ceil(n/2),n); 46 int[] y2=Arrays.copyOfRange(y,0,n/2); 47 n=n/2; 48 findMedian(x2,y2,n); 49 } 50 } 51 }