單調棧
單調棧實際上就是棧,只是限制要比普通的棧更嚴格而已了。要求是每次入棧的元素必須要有序(如果新元素入棧不符合要求,則將之前的元素出棧,直到符合要求再入棧),使之形成單調遞增/單調遞減的一個棧。
- 單調遞增棧:只有比棧頂小的才能入棧,否則就把棧頂出棧后,再入棧。出棧時可能會有一些計算。適用於求解第一個大於該位置元素的數。
- 單調遞減棧:與單調遞增棧相反。適用於求解第一個小於該位置元素的數。
如何判斷
單調遞增/遞減棧是根據出棧后的順序來決定的。例如,棧內順序[1, 2, 6],出棧后順序[6, 2, 1],這就是單調遞減棧。
適用場景
單調棧一般用於解決 第一個大於 xxx 或者 第一個小於 xxx 這種題目。
算法模板
int[] ans = new int[T.Length]; Stack<int> stack = new Stack<int>(); for(int i = 0; i < T.Length; i++) { while(stack.Count > 0 && T[i] > T[stack.Peek()]) { int curI = stack.Pop(); ans[curI] = i - curI; } stack.Push(i); }
哨兵技巧
對於有些時候,如果會用到數組的全部元素,即棧中的元素最后都要出棧,那么很可能因為沒有考慮邊界而無法通過。所以我們可以使用 哨兵法 。
例如在 {1, 3, 4, 5, 2, 9, 6} 末尾添加一個 -1 作為哨兵,變成了 {1, 3, 4, 5, 2, 9, 6, -1} ,這種技巧可以簡化代碼邏輯。
單調棧題目
以下列出了單調棧的問題,供大家參考。
序號 | 題目 | 題解 |
1 | 42. 接雨水(困難) | |
2 | 84. 柱狀圖中最大的矩形(困難) | 暴力法 + 單調棧(哨兵) |
3 | 739. 每日溫度(中等) | 暴力解法 + 單調棧 |
4 | 496. 下一個更大元素 I(簡單) | 暴力解法 + 單調棧 |
5 | 316. 去除重復字母(困難) | |
6 | 901. 股票價格跨度(中等) | |
7 | 402. 移掉K位數字 | |
8 | 581. 最短無序連續子數組 |