文章目录
- 例题
- 739. 每日温度
- 42. 接雨水
- 相关练习
- 1475. 商品折扣后的最终价格
- 901. 股票价格跨度
- 1019. 链表中的下一个更大节点
- 84. 柱状图中最大的矩形
单调栈【基础算法精讲 26】
例题
739. 每日温度
https://leetcode.cn/problems/daily-temperatures/description/
提示:
1 <= temperatures.length <= 10^5
30 <= temperatures[i] <= 100
class Solution {public int[] dailyTemperatures(int[] temperatures) {int n = temperatures.length;int[] ans = new int[n];Deque<Integer> stk = new ArrayDeque<>();for (int i = 0; i < n; ++i) {while (!stk.isEmpty() && temperatures[i] > temperatures[stk.peek()]) {int l = stk.pop();ans[l] = i - l;}stk.push(i);}return ans;}
}
42. 接雨水
https://leetcode.cn/problems/trapping-rain-water/
提示:
n == height.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
每次计算的是一层。(还挺难理解的)
class Solution {public int trap(int[] height) {Deque<Integer> stk = new ArrayDeque<>();int ans = 0;for (int i = 0; i < height.length; ++i) {while (!stk.isEmpty() && height[i] > height[stk.peek()]) {int cur = stk.pop();if (!stk.isEmpty()) {int l = stk.peek();ans += (Math.min(height[i], height[l]) - height[cur]) * (i - l - 1);}}stk.push(i);}return ans;}
}
相关练习
1475. 商品折扣后的最终价格
https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/description/
提示:
1 <= prices.length <= 500
1 <= prices[i] <= 10^3
class Solution {public int[] finalPrices(int[] prices) {int n = prices.length;int[] ans = new int[n];Arrays.setAll(ans, e -> prices[e]);Deque<Integer> stk = new ArrayDeque<>();for (int i = 0; i < n; ++i) {while (!stk.isEmpty() && prices[i] <= prices[stk.peek()]) {int l = stk.pop();ans[l] -= prices[i];}stk.push(i);}return ans;}
}
901. 股票价格跨度
https://leetcode.cn/problems/online-stock-span/
提示:
1 <= price <= 10^5
最多调用 next 方法 10^4 次
就是找每个位置的上一个更大的位置。
class StockSpanner {Deque<int[]> stk = new ArrayDeque();int i;public StockSpanner() {stk.push(new int[]{-1, 0x3f3f3f3f});i = -1;}public int next(int price) {while (price >= stk.peek()[1]) stk.pop();int res = ++i - stk.peek()[0];stk.push(new int[]{i, price});return res;}
}/*** Your StockSpanner object will be instantiated and called as such:* StockSpanner obj = new StockSpanner();* int param_1 = obj.next(price);*/
1019. 链表中的下一个更大节点
https://leetcode.cn/problems/next-greater-node-in-linked-list/description/
提示:
链表中节点数为 n
1 <= n <= 104
1 <= Node.val <= 10^9
先将链表转换成列表,再使用单调栈处理。
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public int[] nextLargerNodes(ListNode head) {List<Integer> nums = new ArrayList<>();while (head != null) {nums.add(head.val);head = head.next;}int n = nums.size();int[] ans = new int[n];Deque<Integer> stk = new ArrayDeque<>();for (int i = 0; i < n; i++) {while (!stk.isEmpty() && nums.get(i) > nums.get(stk.peek())) {ans[stk.pop()] = nums.get(i);}stk.push(i);}return ans;}
}
84. 柱状图中最大的矩形
https://leetcode.cn/problems/largest-rectangle-in-histogram/description/
提示:
1 <= heights.length <=10^5
0 <= heights[i] <= 10^4
用单调栈计算出 l[] 和 r[],这两个数组分别表示 i 左右两边第一个比 height[i] 更小的数。
class Solution {public int largestRectangleArea(int[] heights) {int n = heights.length, ans = 0;int[] l = new int[n], r = new int[n];Arrays.fill(l, -1);Arrays.fill(r, n);Deque<Integer> stk = new ArrayDeque<>();for (int i = 0; i < n; ++i) {while (!stk.isEmpty() && heights[i] < heights[stk.peek()]) {r[stk.pop()] = i;}if (!stk.isEmpty()) l[i] = stk.peek();stk.push(i);}for (int i = 0; i < n; ++i) {ans = Math.max(ans, heights[i] * (r[i] - l[i] - 1));}return ans;}
}
注意这里对数组 l[] 和 r[] 做了初始化,所以能避免下面描述的错误。(即最后结果是正确的)