↓快轉到主要內容
  1. LeetCode/

LeetCode 658: Find K Closest Elements

·2 分鐘· ·
LeetCode Medium Two-Pointers Binary-Search Sliding-Window
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2026-01-25

  • 提交紀錄:Accepted(一次通過)

解題思路
#

陣列已排序,所以最接近 x 的 k 個數一定是一段連續的區間。

我的解法:雙指針從兩端往內縮
#

從整個陣列開始,每次比較兩端哪個離 x 比較遠,把比較遠的丟掉,直到剩下 k 個。距離相同時丟右邊,因為題目規定距離相同時小的數比較近。

class Solution:
    def findClosestElements(self, arr: List[int], k: int, x: int) -> List[int]:
        left, right = 0, len(arr) - 1
        while right - left + 1 > k:
            if abs(arr[right] - x) >= abs(arr[left] - x):
                right -= 1
            else:
                left += 1
        return arr[left:right + 1]

原本開頭還有 x <= arr[0] 和 x >= arr[-1] 的特判,但雙指針本身就能處理這兩種情況,可以拿掉。

更快的解法:二分搜尋窗口起點
#

答案是 arr[lo:lo + k],只要找到起點 lo。比較 arr[mid] 和 arr[mid + k] 誰離 x 比較遠:

  • x - arr[mid] > arr[mid + k] - x:左端比較遠,起點要往右,lo = mid + 1。
  • 否則起點在 mid 或更左邊,hi = mid。
class Solution:
    def findClosestElements(self, arr: List[int], k: int, x: int) -> List[int]:
        lo, hi = 0, len(arr) - k
        while lo < hi:
            mid = (lo + hi) // 2
            if x - arr[mid] > arr[mid + k] - x:
                lo = mid + 1
            else:
                hi = mid
        return arr[lo:lo + k]

這裡刻意不用 abs:用帶號的差值比較,x 在兩者外側時也能判斷方向。

複雜度
#

解法時間
雙指針O(n - k)
二分搜尋O(log(n - k) + k)

空間都是 O(1),不算輸出。

要特別避免的錯誤
#

  • 平手時丟掉左邊:題目規定平手時值小的優先,所以要丟右邊。
  • 二分版用 abs 比較:arr[mid] 和 arr[mid + k] 相等時,abs 會讓窗口往錯的方向移。
  • 先排序整個陣列依距離挑 k 個,再排序回來:O(n log n),沒用到已排序的條件。

面試口說整理
#

陣列已排序,答案一定是一段長度 k 的連續區間。最直接的做法是雙指針從兩端往內縮,每次丟掉離 x 比較遠的一端,平手時丟右邊,O(n - k)。更快的是二分搜尋起點:比較 x - arr[mid] 和 arr[mid + k] - x,左端比較遠就往右找,時間 O(log(n - k) + k)。

相關文章

LeetCode 209: Minimum Size Subarray Sum
·1 分鐘
LeetCode Daily Medium Array Sliding-Window Two-Pointers Prefix-Sum Binary-Search
滑動視窗與雙指針,最小化子陣列長度(總和 ≥ target)。
LeetCode 1574: Shortest Subarray to be Removed to Make Array Sorted
·1 分鐘
LeetCode Medium Two-Pointers Binary-Search Array Monotonic-Stack
LeetCode 1574 解題筆記:留下來的一定是「非遞減前綴 + 非遞減後綴」;先找出最長前綴和後綴,再用雙指針把兩段接起來
LeetCode 2563: Count the Number of Fair Pairs
·2 分鐘
LeetCode Medium Two-Pointers Sorting Binary-Search Array
LeetCode 2563 解題筆記:把「和落在 [lower, upper]」拆成「和 <= upper」減「和 <= lower - 1」,每個都用排序後的對撞指針 O(n) 數
LeetCode 633: Sum of Square Numbers
·2 分鐘
LeetCode Medium Two-Pointers Math Binary-Search
LeetCode 633 解題筆記:a 從 0、b 從 isqrt(c) 開始對撞;平方和太大 b 減一,太小 a 加一;注意 0 也算、a 可以等於 b、浮點數開根號的誤差
LeetCode 1498: Number of Subsequences That Satisfy the Given Sum Condition
·2 分鐘
LeetCode Medium Two-Pointers Sorting Binary-Search Array
LeetCode 1498 解題筆記:子序列只看最小值和最大值,排序後順序無關;固定最小值 nums[left],中間的元素任意選,共 2^(right - left) 種
LeetCode 1712: Ways to Split Array Into Three Subarrays
·2 分鐘
LeetCode Medium Binary-Search Prefix-Sum Two-Pointers
LeetCode 1712 解題筆記:固定第一刀,第二刀的合法範圍用兩次 bisect 或兩個單調指針找出來