[牛客算法系列] 在另個排序陣列中找到第k小的數
阿新 • • 發佈:2018-12-14
題目
- 給定兩個有序陣列arr1,arr2, 再給定一個整數k, 返回所有數中第k 小的數。
- 比如 arr1 = [1,2,3,4,5], arr2 = [3,4,5], k =1. 1 是所有數中第一小的數,所以返回1. arr1 = [1,2,3], arr2 = [3,4,5,6] , k = 4. 3 是所有數中第4 小的數,所以返回3.
- Note: 如果arr1 的長度為N, arr2 的長度為M, 時間複雜度要達到O(log(min{M,N})),額外空間複雜度O(1).
分析題目
- 本題深度的利用“在兩個長度相等的排序陣列中找到上中位數”
- 分四種情況 詳見程式碼
程式碼
//兩個長度相等的排序陣列中找到上中位數
public int getUpMedian(int[] a1, int s1, int e1, int[] a2, int s2, int e2) {
int mid1 = 0;
int mid2 = 0;
int offset = 0;
while(s1 < e1){
mid1 = (s1 + e1) / 2;
mid2 = (s2 + e2) / 2;
offset = ((e1 - s1 + 1) & 1 ) ^ 1; //偶數offset 為1, 奇數為0
if(a1[mid1] > a2[mid2]){
e1 = mid1;
s2 = mid2 + offset;
}else if(a1[mid1] < a2[mid2]){
s1 = mid1 + offset;
e2 = mid2;
}else{
return a1[mid1];
}
}
return Math.min(a1[s1],a2[s2]);
}
public int findKthNum(int[] arr1, int[] arr2, int kth){
if(arr1 == null || arr2 == null){
throw new RuntimeException("Your arr is invalid!");
}
// ① kth < 1 或大於 兩個陣列長度的和,則k 無效
if(kth < 1 || kth > arr1.length + arr2.length){
throw new RuntimeException("K is invalid");
}
int[] longs = arr1.length >= arr2.length ? arr1 : arr2;
int[] shorts = arr1.length < arr2.length ? arr1 : arr2;
int l = longs.length;
int s = shorts.length;
//② kth 小於較小陣列的長度(從arr1,arr2 中分別拿k 個 求上中位數)
if(kth <= s){
return getUpMedian(shorts, 0, kth - 1, longs, 0, kth - 1)
}
//③ kth 大於較長陣列的長度。先判斷兩個陣列在kth 位置的大小
if(kth > l){
if(shorts[kth - l -1] >= longs[ l -1]){
return shorts[kth -l -1];
}
if(longs[kth -s -1] >= shorts[s - 1]){
return longs[kth -s -1];
}
return getUpMedian(shorts, kth -l , s -1, longs, kth -s , l - 1);
}
//④ kth 在兩者之間。先判斷長陣列中kth 位置的大小
if(longs[kth -s -1] >= shorts[s -1]){
return longs[kth -s -1];
}
return getUpMedian(shorts, 0, s-1, longs, kth -s,, kth - 1)
}