Joseph Chen
EP.06 學了基礎 Stack,這篇進階:Monotonic Stack(單調棧)。
Monotonic Stack 的概念很簡單——在 push 新元素之前,先把 stack 裡所有「不符合單調條件的元素」pop 出來。 這個 pop 的動作不是多餘的,每個被 pop 出來的元素,都正好找到了它的「下一個更大值」。
這個模式能把許多 O(n²) 的「找下一個更大/更小」問題,降到 O(n)。
Monotonic Stack 是什麼?
單調遞增棧(底大頂小)
Stack 從底到頂值遞減(頂端永遠是最小的)。 push 時,把所有比新元素大的 pop 掉。 用來找「右邊第一個更大的元素」。
單調遞減棧(底小頂大)
Stack 從底到頂值遞增(頂端永遠是最大的)。 push 時,把所有比新元素小的 pop 掉。 用來找「右邊第一個更小的元素」。
通用框架
關鍵:stack 裡存的通常是 index(不是值),因為我們往往需要計算距離或對應回原陣列的值。
Part 1 — Daily Temperatures
#739 · Medium · 幾天後會更暖?
題目
給一個每日氣溫陣列 temperatures, 回傳一個陣列 answer,answer[i] 代表第 i 天之後幾天會迎來更高溫,若之後沒有更高溫則為 0。
temperatures = [73,74,75,71,69,72,76,73]
answer = [1, 1, 4, 2, 1, 1, 0, 0]
視覺化:棒狀圖 + stack 變化
temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
為什麼是 O(n)?
每個 index 最多被 push 一次、pop 一次,所以 while 迴圈裡的所有 pop 操作加起來也是 O(n)。 外層 for 迴圈 O(n),總體 O(n)——這就是 Monotonic Stack 的威力。
Part 2 — Next Greater Element I
#496 · Easy · 找 nums2 中的下一個更大值
題目
nums1 是 nums2 的子集。 對 nums1 中的每個元素,找出它在 nums2 中右邊第一個更大的元素,若不存在回傳 -1。
nums1 = [4,1,2], nums2 = [1,3,4,2]
Output: [-1,3,-1]
4 的右邊沒有更大的 → -1;1 的右邊第一個更大的是 3;2 的右邊沒有更大的 → -1
思路:先預處理 nums2,再查表
這題的關鍵不是直接對 nums1 操作,而是先對 nums2 做一次 Monotonic Stack, 建立一張「每個值 → 其下一個更大值」的 HashMap。 然後對 nums1 的每個元素,直接查這張表就好。
nums2 = [1, 3, 4, 2] 的預處理
最終 HashMap:{1:3, 3:4, 4:-1, 2:-1}
和 #739 的差異
#739 存的是 index(因為需要計算距離 i - idx); #496 存的是 值本身(只需要查「這個值對應的下一個更大值」,不需要位置資訊)。 根據需求決定 stack 存 index 還是值,是 Monotonic Stack 最常見的判斷點。
Part 3 — Trapping Rain Water
#42 · Hard · 接了多少雨水?
題目
給一個表示地形高度的陣列,計算下雨後整個地形能接住多少單位的雨水。
height = [0,1,0,2,1,0,1,3,1,0,1,2]
Output: 6
高度示意(height = [0,1,0,2,1,0,1,3,1,0,1,2])
橘色:左右最高牆;藍色:最高柱。中間低窪處可接水
解法一:Two Pointers(推薦記這個)
每個位置能接的水量 = min(左邊最高, 右邊最高) - 自身高度。 用左右兩個指針,從低的那側往中間走,始終能保證當前那側的「最高牆」是確定的。
Two Pointers 直覺
• left 指向左端,right 指向右端,left_max 和 right_max 追蹤各側見過的最大值
• 若 height[left] < height[right]:左側牆較矮,左側積水量由 left_max 決定
→ 積水 = left_max - height[left],left 右移
• 反之,處理右側,right 左移
解法二:Monotonic Stack
用單調遞減棧,當遇到比棧頂更高的柱子時,就可以計算「兩個較高柱子夾著中間凹陷」能接的水量。 這是橫向計算積水(一層一層算),Two Pointers 是縱向(一列一列算)。兩種思路都正確。
Two Pointers
- ✅ O(1) 空間,更優
- ✅ 程式碼更短,更直觀
- ✅ 面試首選解法
Monotonic Stack
- ✅ 思維框架和其他題一致
- ✅ 橫向計算,適合變形題
- ❕ O(n) 空間
三題統一對比
| 題目 | Stack 存什麼 | pop 時做什麼 | 複雜度 |
|---|---|---|---|
| #739 Daily Temperatures | index | ans[idx] = i - idx | O(n) / O(n) |
| #496 Next Greater Element | 值 | map[val] = cur_val | O(n+m) / O(n) |
| #42 Trapping Rain Water | index | 計算左牆右牆夾住的積水面積 | O(n) / O(n) |
識別 Monotonic Stack 題目的訊號
- →「找右邊(或左邊)第一個更大/更小的元素」
- →「計算每個元素作為最大/最小值時能影響的範圍」
- →暴力解是兩層 for loop O(n²),但感覺「每個元素只會被處理一次」
- →stack 裡的元素一直在「等待」找到自己的答案(被 pop 時就是找到答案的時刻)
這篇學到什麼
上一篇
EP.17 — Intervals
Merge、Non-overlapping、Meeting Rooms II
下一篇
EP.19 — Trie
Implement Trie、Add and Search