給定兩個已經排序好的數組,找到兩者所有元素中第 k 大的元素。假設爲A,B都按升序排列。
方法一: 直接 merge 兩個數組(即將兩個已排好序的數組合併爲一個排好序的新數組(m+n個元素),然後求第 k 大的元素,時間複雜度爲O(m + n);可以用一個計數器,
記錄當前已經找到第 m 大的元素了。同時我們使用兩個指針
pA 和 pB,分別指向 A 和 B 數組的第一個元素,使用類似於 merge sort 的原理,如果數組 A 當前元素小,那麼 pA++,同時 m++;如果數組
B 當前元素 小,那麼 pB++,同時 m++。最終當 m 等於 k 的時候,就得到了我們的答案,O(k)時間,O(1) 空間。但是,當 k 很接近 m + n 的時候,這個方法時間複雜還是 O(m + n) 。
C++代碼:
int findKthMaxNumOfArrays(int A[],int m,int B[],int n,int k)
{
int *pA=A;
int *pB=B;
int i=0;
int j=0;
int cur=0;
while(i<m&&j<n)
{
if(A[i]<B[j])
{
cur++;
if(cur==k) return A[i];
i++;
}
else
{
cur++;
if(cur==k) return B[j];
j++;
}
}
while(i<m)
{
cur++;
if(cur==k) return A[i];
i++;
}
while(j<n)
{
cur++;
if(cur==k) return B[j];
j++;
}
}
方法二: 由於 A 和 B 都是有序
的,利用這裏面的信息,類似於二分查找。時間複雜度可以縮短到
假設 A 和 B 的元素個數都大於 k/2,我們將 A 的第 k/2 個元素(即 A[k/2-1])和 B 的第 k/2個元素(即 B[k/2-1])進行比較,
有以下三種情況(爲了簡化這裏先假設 k 爲偶數,所得到的結論對於 k 是奇數也是成立的):
• A[k/2-1] == B[k/2-1]
• A[k/2-1] > B[k/2-1]
• A[k/2-1] < B[k/2-1]
如果 A[k/2-1] < B[k/2-1],意味着 A[0] 到 A[k/2-1 ]的肯定在 A ∪ B 的 top k 元素的範圍內,換句話說,A[k/2-1 ]不可能大於 A ∪ B 的第 k 大元素。因此,我們可以放心的刪除 A 數組的這 k/2 個元素。同理,當 A[k/2-1]
> B[k/2-1] 時,可以刪除 B 數組的 k/2 個元素。當 A[k/2-1] == B[k/2-1] 時,說明找到了第 k 大的元素,直接返回 A[k/2-1] 或 B[k/2-1]
因此,我們可以寫一個遞歸函數。那麼函數終止條件如下:
• 當 A 或 B 是空時,直接返回 B[k-1] 或 A[k-1];
• 當 k=1 是,返回 min(A[0], B[0]);
• 當 A[k/2-1] == B[k/2-1] 時,返回 A[k/2-1] 或 B[k/2-1]
int findKthMaxNumOfArrays(int A[],int m,int B[],int n,int k)
{
if(m>n)
return findKthMaxNumOfArrays(B,n,A,m,k); //假設m永遠<=n;
if(m==0)
return B[k-1];
if(k==1)
return ((A[0]>=B[0]?B[0]:A[0]));
int k2=k>>1;
int pA=((k2>=m)?m:k2);
int pB=k-pA;
if(A[pA-1]<B[pB-1])
return findKthMaxNumOfArrays(A+pA,m-pA,B,n,k-pA);
else if(A[pA-1]>B[pB-1])
return findKthMaxNumOfArrays(A,m,B+pB,n-pB,k-pB);
else
return A[pA-1];
}
方法三、判斷a[mid_a] 與 b[mid_b]的關係(同二類似)
如果A[mida] < B[mid_b]
1)k小於等於mida + midb + 1,那麼B數組從mid_b開始就沒有用了,縮小B的搜索範圍
2)k大於mida + midb + 1, 那麼A數組從low到mid_a開始就沒用了,縮小A的搜索範圍
3)終止條件是 A搜索完 返回B中元素或者相反
找到兩者所有元素的中位數
int findMedianSortedArrays(int A[], int m, int B[], int n)
{
int total = m + n;
if (total & 0x1)
return findKth(A, m, B, n, total / 2 + 1); //m+n爲奇數
else
return (findKth(A, m, B, n, total / 2)
+ findKth(A, m, B, n, total / 2 + 1)) / 2; //m+n爲偶數
}