【算法】单调栈 每日温度 接雨水

单调栈【基础算法精讲 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[] 做了初始化,所以能避免下面描述的错误。(即最后结果是正确的)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei *

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值