1. 程式人生 > >[牛客算法系列] 在另個排序陣列中找到第k小的數

[牛客算法系列] 在另個排序陣列中找到第k小的數

題目

  • 給定兩個有序陣列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) }