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

LeetCode 1793: Maximum Score of a Good Subarray

·1 分鐘· ·
LeetCode Hard Two-Pointers Greedy Binary-Search Array Monotonic-Stack
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

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

  • 提交紀錄:Wrong Answer ×3 → Accepted

解題思路
#

好的子陣列一定包含 k,所以從 [k, k] 開始,每次往左或往右擴一格,長度從 1 長到 n。

往鄰居比較大的那一邊擴:分數是「最小值 × 長度」,同樣的長度下,最小值越大越好。往大的那邊走,最小值降得最少。每擴一格就用目前的最小值 × 長度更新答案。

到邊界時只能往另一邊走,直到兩邊都到底。

這個貪心也可以用單調棧的角度理解:對每個 nums[i] 當最小值,找它左右能延伸的最遠範圍,範圍包含 k 才算數,跟 LeetCode 84 的直方圖最大矩形同一類。

我的嘗試
#

我的寫法是計算「往左擴」和「往右擴」之後的分數,往分數高的那邊走。三次 WA 都是邊界和更新的問題:

版本問題
第一版往左擴的長度少算 1,沒有更新目前的最小值,右邊已經到底還會往右走。例如 nums = [1, 1]、k = 1:答案是 2,回傳 1
第二版往右擴時,答案卻用往左擴的分數更新。例如 nums = [1, 1]、k = 0:答案是 2,回傳 1
第三版迴圈條件是 start >= 0 and end <= n - 1,到邊界的那一邊分數設成目前答案;平手時走到不能走的那一邊,start 變成 -1,迴圈提早結束,另一邊沒擴完。例如 nums = [2, 1, 1]、k = 0:整段 1 × 3 = 3 是答案,回傳 2

最後改成 while start > 0 or end < n - 1,並且到邊界時強制往另一邊走,就 AC 了。

正確解法
#

class Solution:
    def maximumScore(self, nums: List[int], k: int) -> int:
        n = len(nums)
        i = j = k
        cur_min = best = nums[k]
        while i > 0 or j < n - 1:
            if i == 0 or (j < n - 1 and nums[j + 1] > nums[i - 1]):
                j += 1                             # 往右(左邊到底,或右鄰居比較大)
                cur_min = min(cur_min, nums[j])
            else:
                i -= 1                             # 往左
                cur_min = min(cur_min, nums[i])
            best = max(best, cur_min * (j - i + 1))
        return best

這裡直接比較兩個鄰居的值,比原本比較「擴張後的分數」簡單,效果一樣。

複雜度
#

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

要特別避免的錯誤
#

  • 擴張後忘了更新最小值。
  • 到邊界時還往那一邊走,或迴圈提早結束、另一邊沒擴完。
  • 長度是 j - i + 1。

面試口說整理
#

好的子陣列一定包含 k,所以我從 k 開始往兩邊擴,每次往鄰居比較大的那一邊走,因為同樣長度下最小值越大分數越高,往大的那邊最小值降得最少。每擴一格用目前最小值乘長度更新答案,一邊到底就只往另一邊。時間 O(n)。也可以用單調棧找每個元素當最小值的範圍,只算包含 k 的。

相關文章

LeetCode 611: Valid Triangle Number
·1 分鐘
LeetCode Medium Array Two-Pointers Binary-Search Greedy
LeetCode 611 解題筆記:排序後固定最長邊 k,左右指針找兩短邊:和夠大時中間的都可以,一次加 j - i 個
LeetCode 3555: Smallest Subarray to Sort in Every Sliding Window
·1 分鐘
LeetCode Medium Two-Pointers Greedy Sorting Array Monotonic-Stack
LeetCode 3555 解題筆記:每個長度 k 的視窗都是一次 LeetCode 581;n 只有 1000,對每個視窗跑 O(k) 的兩次掃描即可
LeetCode 581: Shortest Unsorted Continuous Subarray
·1 分鐘
LeetCode Medium Two-Pointers Greedy Sorting Array Monotonic-Stack
LeetCode 581 解題筆記:從左往右記最大值,最後一個比最大值小的位置是右界;從右往左記最小值,最後一個比最小值大的位置是左界
LeetCode 2972: Count the Number of Incremovable Subarrays II
·1 分鐘
LeetCode Hard Two-Pointers Binary-Search Array
LeetCode 2972 解題筆記:刪掉一段後留下嚴格遞增的前綴 + 後綴;對每個合法的前綴結尾,用只往右走的指針找第一個能接上的後綴起點,後面的起點都能選
LeetCode 1574: Shortest Subarray to be Removed to Make Array Sorted
·1 分鐘
LeetCode Medium Two-Pointers Binary-Search Array Monotonic-Stack
LeetCode 1574 解題筆記:留下來的一定是「非遞減前綴 + 非遞減後綴」;先找出最長前綴和後綴,再用雙指針把兩段接起來
LeetCode 1989: Maximum Number of People That Can Be Caught in Tag
·1 分鐘
LeetCode Medium Two-Pointers Greedy Array
LeetCode 1989 解題筆記:鬼從左到右,每個鬼抓範圍內最左邊、還沒被抓的人;用一個只往右走的指針指向下一個候選人