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

LeetCode 220: Contains Duplicate III

·2 分鐘· ·
LeetCode Hard Sliding-Window Bucket-Sort Ordered-Set Sorting Array
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-01-10

  • 提交紀錄:Wrong Answer ×2 → Output Limit Exceeded → Accepted

解題思路
#

兩個條件:index 差 <= indexDiff、值差 <= valueDiff。

  • index 條件用滑動視窗:只保留最近 indexDiff 個數。
  • 值條件用分桶:桶大小 size = valueDiff + 1,x 放在第 x // size 個桶。
    • 同一個桶裡的兩個數,差一定 <= valueDiff,直接回傳 True。所以每個桶最多只會有一個數。
    • 差 <= valueDiff 的數也可能在相鄰的桶,所以再檢查 b - 1 和 b + 1 兩個桶。
    • 更遠的桶,差一定 > valueDiff。

視窗移動時,把 nums[i - indexDiff - 1] 所在的桶刪掉。

Python 的 // 對負數是往下取整,-1 // 3 == -1,負數也能正確分桶。

我的嘗試
#

版本問題
第一、二版刪除過期元素時用 index 當 key(del buckets[i - indexDiff - 1]),但桶的 key 是值除以大小;相鄰桶的比較寫成 < valueDiff,少了等於。例如 nums = [2, 5]、indexDiff = 2、valueDiff = 3:`
第三版 OLE修好了,但留著 print(buckets)
AC拿掉 print

正確解法
#

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], indexDiff: int, valueDiff: int) -> bool:
        size = valueDiff + 1
        buckets = {}                               # 桶編號 -> 桶裡唯一的數
        for i, x in enumerate(nums):
            if i > indexDiff:
                del buckets[nums[i - indexDiff - 1] // size]   # 移出視窗
            b = x // size
            if b in buckets:
                return True                        # 同一個桶,差一定 <= valueDiff
            if b - 1 in buckets and x - buckets[b - 1] <= valueDiff:
                return True
            if b + 1 in buckets and buckets[b + 1] - x <= valueDiff:
                return True
            buckets[b] = x
        return False

過期的那個數當初一定有放進桶裡,而且沒被覆蓋(覆蓋代表同桶,早就回傳了),所以 del 一定找得到。

複雜度
#

時間 O(n),空間 O(min(n, indexDiff))。另一種做法是用有序集合(SortedList)維護視窗,查詢 >= x - valueDiff 的最小值,時間 O(n log k)。

要特別避免的錯誤
#

  • 刪除時用 index 當 key:桶的 key 是 值 // size。
  • 相鄰桶的比較要用 <=。
  • 桶大小是 valueDiff + 1,不是 valueDiff(valueDiff = 0 時會除以 0)。
  • 提交前留著 print。

面試口說整理
#

index 條件用滑動視窗,只保留最近 indexDiff 個數;值的條件用分桶,桶大小是 valueDiff + 1。同一個桶裡兩個數一定符合,所以每個桶最多一個數;再檢查左右兩個相鄰的桶,更遠的桶不可能符合。視窗移動時刪掉過期數字所在的桶。時間 O(n)。

相關文章

LeetCode 164: Maximum Gap
·1 分鐘
LeetCode Medium Bucket-Sort Radix-Sort Sorting Array
LeetCode 164 解題筆記:最大間距至少是平均間距,桶子寬度不超過它時,最大差一定在相鄰的非空桶子之間;每個桶子只記最小和最大值,O(n)
LeetCode 3634: Minimum Removals to Balance Array
·1 分鐘
LeetCode Medium Sliding-Window Sorting Binary-Search Array
LeetCode 3634 解題筆記:排序後留下來的一定是連續一段;對每個最小值 nums[left],用只往右走的指針找能留到哪裡,刪掉兩邊剩下的
LeetCode 594: Longest Harmonious Subsequence
·1 分鐘
LeetCode Easy Array Hash-Table Sliding-Window Sorting
LeetCode 594 解題筆記:子序列不用連續,所以只要計數,每個 x 看 x 和 x + 1 的次數加起來
LeetCode 2156: Find Substring With Given Hash Value
·1 分鐘
LeetCode Hard Sliding-Window Rolling-Hash String
LeetCode 2156 解題筆記:雜湊的第一個字元乘 p^0,從右往左滑動時只要乘 p 再加新字元、扣掉 p^k 倍的出去字元,不需要除法;modulo 不一定是質數,不能用模反元素
LeetCode 2953: Count Complete Substrings
·2 分鐘
LeetCode Hard Sliding-Window Hash-Table String
LeetCode 2953 解題筆記:先在相鄰字元差 > 2 的地方切段;每段枚舉有幾種字元 d,視窗長度固定是 d × k,維護「剛好出現 k 次的字元數」
LeetCode 3795: Minimum Subarray Length With Distinct Sum At Least K
·1 分鐘
LeetCode Medium Sliding-Window Hash-Table Array
LeetCode 3795 解題筆記:求最短的可變視窗;同一個值只算一次,記錄每個值最後出現的位置,左邊界移出的是最後一次出現才扣掉