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

LeetCode 2054: Two Best Non-Overlapping Events

·1 分鐘· ·
LeetCode Medium Dynamic-Programming Binary-Search Sorting Heap
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: medium 第一次嘗試:2026-02-04

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

解題思路
#

跟 LeetCode 1235 同一類,但只能選最多兩個,所以不需要完整的 DP:

  • 把活動依結束時間排序,算前綴最大值 prefix_best[j] = 前 j 個活動裡的最大價值。
  • 對每個活動 (s, e, v) 當作「第二個」,用二分搜尋找最後一個 end < s 的活動(題目的時間是包含兩端的,所以要嚴格小於),答案是 v + prefix_best。
  • 也要考慮只選一個。

另一種做法是掃描線:把每個活動拆成「開始」和「結束 + 1」兩個事件排序,掃過去時維護已結束活動的最大價值,遇到開始事件就更新答案。我當時 AC 的是掃描線版本。

我的解法
#

from bisect import bisect_left

class Solution:
    def maxTwoEvents(self, events: List[List[int]]) -> int:
        events.sort(key=lambda e: e[1])            # 依結束時間
        ends = [e for _, e, _ in events]
        prefix_best = []
        m = 0
        for _, _, v in events:
            m = max(m, v)
            prefix_best.append(m)

        ans = 0
        for s, _, v in events:
            i = bisect_left(ends, s) - 1           # 最後一個 end < s
            ans = max(ans, v + (prefix_best[i] if i >= 0 else 0))
        return ans

掃描線版本:

class Solution:
    def maxTwoEvents(self, events: List[List[int]]) -> int:
        points = []
        for s, e, v in events:
            points.append((s, 1, v))               # 1:開始
            points.append((e + 1, 0, v))           # 0:結束(e + 1 才能接新的)
        points.sort()                              # 同一時間先處理結束
        ans = ended_best = 0
        for _, kind, v in points:
            if kind == 1:
                ans = max(ans, v + ended_best)
            else:
                ended_best = max(ended_best, v)
        return ans

複雜度
#

時間 O(n log n),空間 O(n)。

要特別避免的錯誤
#

  • 時間是閉區間:一個在 t 結束、另一個在 t 開始算重疊,所以是 end < start。
  • 掃描線同一時間要先處理結束事件,(time, 0) 會排在 (time, 1) 前面。

面試口說整理
#

最多選兩個,所以對每個活動,我只要知道在它開始之前就結束的活動裡價值最大的是多少。把活動依結束時間排序、算前綴最大值,再對每個活動二分搜尋最後一個結束時間小於它開始時間的位置,加起來取最大。也可以用掃描線做。時間 O(n log n)。

相關文章

LeetCode 3323: Minimize Connected Groups by Inserting Interval
·1 分鐘
LeetCode Medium Sliding-Window Sorting Binary-Search Array
LeetCode 3323 解題筆記:先合併區間;新區間能把第 l 到 r 組連起來 ⇔ 第 r 組的起點 − 第 l 組的終點 <= k;滑動視窗找一次能連起來最多組
LeetCode 1838: Frequency of the Most Frequent Element
·1 分鐘
LeetCode Medium Sliding-Window Sorting Greedy Prefix-Sum Binary-Search Array
LeetCode 1838 解題筆記:排序後,把視窗裡的數都加到 nums[right] 的花費是 nums[right] × 長度 − 視窗總和;花費 > k 就縮左邊
LeetCode 2271: Maximum White Tiles Covered by a Carpet
·1 分鐘
LeetCode Medium Sliding-Window Greedy Sorting Prefix-Sum Binary-Search Array
LeetCode 2271 解題筆記:地毯的左端放在某段白磚的起點一定不會更差;排序後用雙指針,完整蓋住的段累加,最後一段只算部分
LeetCode 3634: Minimum Removals to Balance Array
·1 分鐘
LeetCode Medium Sliding-Window Sorting Binary-Search Array
LeetCode 3634 解題筆記:排序後留下來的一定是連續一段;對每個最小值 nums[left],用只往右走的指針找能留到哪裡,刪掉兩邊剩下的
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 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) 種