給定整數陣列 nums 和兩個整數 left、right(left <= right),回傳最大元素介於 [left, right] 之間的子陣列個數(子陣列必須連續)。
範例:nums = [2, 1, 4, 3], left = 2, right = 3
定義輔助函式 count(bound):計算最大元素 ≤ bound 的子陣列個數。
答案即為:count(right) - count(left - 1)
count(right) 計算最大值 ≤ right 的子陣列數(包含最大值恰好在 [left, right] 和最大值 < left 兩類)count(left - 1) 計算最大值 < left 的子陣列數count(bound) 的實作:維護當前連續「最大值 ≤ bound」的子陣列起始點。遇到 nums[i] > bound 時重置計數;否則當前以 i 結尾的合法子陣列有 i - start + 1 個(start 為上次重置點的下一位置)。
遍歷陣列,對每個元素判斷其值所屬範圍:
left_bound = i,以此元素結尾的子陣列無效。prev = i(最後一個值在範圍內的索引);以 i 結尾的有效子陣列數為 i - left_bound。prev - left_bound(沿用上次在範圍內的元素決定的數量)。兩種思路都是 O(n) 時間,思路一更容易推廣,思路二更節省程式碼行數。
O(n),其中 n 為陣列長度。
count 函式被呼叫兩次,每次線性遍歷,共 O(2n) = O(n)。O(1),只使用了常數個額外變數,不需要額外陣列。
Approach 1: count(nums, bound): 1. result = 0, cur = 0 2. For each x in nums: a. If x <= bound: cur += 1 b. Else: cur = 0 c. result += cur 3. Return result numSubarrayBoundedMax(nums, left, right): 1. Return count(nums, right) - count(nums, left - 1) Approach 2 (single pass): 1. leftBound = -1, prev = -1, result = 0 2. For i from 0 to n-1: a. If nums[i] > right: leftBound = i b. If nums[i] >= left: prev = i c. result += prev - leftBound 3. Return result
雙重迴圈枚舉所有子陣列 [i, j],用第三層迴圈(或維護滾動最大值)計算子陣列最大元素,判斷是否在 [left, right] 內。
利用單調棧追蹤每個元素作為子陣列最大值的範圍(左右邊界),然後統計每個元素作為最大值、且值在 [left, right] 內的子陣列數。
count(right) - count(left-1) 更複雜;需要正確處理重複元素的邊界(嚴格 vs 非嚴格)。預先統計以每個位置結尾的、最大值在各範圍的子陣列數,建立前綴計數表。
子陣列最小值在 [left, right] 之間:與本題類似,只需把「最大值」換成「最小值」,同樣可以用 count(right) - count(left-1) 的框架,其中 count(bound) 統計最小值 ≤ bound 的子陣列數(改為遇到 nums[i] > bound 時繼續計數,遇到 nums[i] <= bound 時記錄)。
最大值等於 target 的子陣列數:若要求最大值恰好等於某個值 target,即 count(target) - count(target - 1),是本題 left = right = target 的特例。
推廣:最大值與最小值都在範圍內:若要求子陣列的最大值在 [maxL, maxR] 且最小值在 [minL, minR] 之間,問題複雜度顯著增加,需要同時追蹤最大值和最小值的有效段,可結合兩個指標或使用單調雙端佇列(monotonic deque)。