前往
大廳
主題

LeetCode - 658. Find K Closest Elements 解題心得

Not In My Back Yard | 2021-10-28 00:00:03 | 巴幣 0 | 人氣 398

題目連結:


題目意譯:
給定一個已排序陣列 arr 以及兩整數 k 和 x,回傳陣列中 k 個距離 x 最近的整數。結果應以升序排序後回傳。

一整數 a 比整數 b 更接近 x,如果:
|a - x| < |b - x|
|a - x| == |b - x| 且 a < b

限制:
1 ≦ k ≦ arr.length
1 ≦ arr.length ≦ 10 ^ 4
arr 以升序排序。
-10 ^ 4 ≦ arr[i] 、 x ≦ 10 ^ 4



範例測資:
範例 1:
輸入: arr = [1,2,3,4,5], k = 4, x = 3
輸出: [1,2,3,4]

範例 2:
輸入: arr = [1,2,3,4,5], k = 4, x = -1
輸出: [1,2,3,4]


解題思維:
二分搜尋法(Binary Search)即可。

定義下界 L = 0 、 上界 U = arr.length - k,重複以下步驟直到 L 不小於 U 為止:
令 M = floor((L + U) ÷ 2),其中 floor 為下高斯函數(對於正數來說等價於無條件捨去小數點後的數字)。

如果 x - arr[M] 小於 arr[M + k] - x 的話,則我們需要將下界 L 提高至 M + 1;反之則需要將上界 U 降低至 M。



最後 arr[L] 、 arr[L + 1] 、 …… 、 arr[L + k - 1] 這個序列即是所求。

那麼為什麼中間的 x - arr[M] 與 arr[M + k] - x 可以判斷誰比較靠近呢?可以看到,arr[M] 是區間的左端點而 arr[M + k] 是區間的右端點右邊的元素,且它們將會有以下三種情形:
一:arr[M] 和 arr[M + k] 都小於 x,此時 x - arr[M] 大於 arr[M + k] - x。因為所求的區間左端點應位於 M + 1 ~ U,而不是 L ~ M。其中 arr[M + k + 1] 可能就會超過 x 了,所以不能將 L 更新為 M + k。

二:arr[M] 和 arr[M + k] 都大於 x,此時 x - arr[M] 小於 arr[M + k] - x。因為所求的區間左端點應位於 L ~ M,而不是 M + 1 ~ U。

三:x 位於 arr[M] 和 arr[M + k] 之間(arr[M] ≦ x ≦ arr[M + k]),此時就是題目敘述中的 |a - x| 與 |b - x| 的大小關係比較。當 x - arr[M] 大於 arr[M + k] - x,等同於狀況一;反之當 x - arr[M] 小於等於 arr[M + k] - x 時,視為等同於狀況二(等於時的情況是因為題目有敘述 |a - x| == |b - x| 且 a < b 這個條件)。

因此這樣便可以判斷左端點應位於何處,便可以從中推得所求序列。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作