Leetcode: monotonic queue总结

很不擅长的一部分内容,值得总结一下
monotonic queue的应用有
求previous less element(PLE), next greater element(NLE), previous greater element(PGE), next greater element(NGE)。以求NGE为例:

从前往后扫,维护一个decreasing monotonic queue

public int[] NGE(int[] nums) {
    int[] res = new int[nums.length];
    Arrays.fill(res, -1); // nums.length表示不存在NGE
    Stack s = new Stack<>();
    for (int i = 0; i < nums.length; i ++) {
        while (!s.isEmpty() && nums[i] > nums[s.peek()])
            res[s.pop()] = i;
        s.push(i);
    }
    return res;
}

求previous greater element(PGE)

从前往后扫维护一个decreasing monotonic queue

public int[] PGE(int[] nums) {
    int[] res = new int[nums.length];
    Stack s = new Stack<>();    
    for (int i = 0; i < nums.length; i ++) {
        while (!s.isEmpty() && nums[i] >= s.peek())
            s.pop();
        res[i] = s.isEmpty() ? -1 : s.peek();
    }
    return res;
}

decreasing monotonic queue可以求:NGE和PGE
increasing monotonic queue可以求:NLE和PLE

以上都是严格大于的情况,求previous严格情况是>=,非严格情况>。求next则相反
用monotonic queue解决问题时需要考虑使用decreasing queue还是increasing queue,想清楚这个问题再实现代码。

有的时候我们需要同时求PLE和NLE,可以用两个数组分别存储每个位置对应的PLE和NLE,还可以仅用一个monotonic queue。要求PLE和NLE时维护一个increasing stack,求PGE和NGE时维护一个decreasing stack,详见下面两题
42. Trapping Rain Water
84. Largest Rectangle in Histogram
Trapping Rain Water这题用stack模拟装水的情况,因此是decreasing monotonic queue,找NGE和PGE

class Solution {
    public int trap(int[] height) {
        Stack stack = new Stack<>();
        int res = 0;
        for (int i = 0; i < height.length; i ++) {
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                int h = height[stack.pop()];
                int l = stack.isEmpty() ? -1 : stack.peek();
                int area = (i-l-1) * (Math.min(height[i], l == -1 ? 0 : height[l])-h);
                area = Math.max(0, area);
                res += area;
            }
            stack.push(i);
        }
        return res;
    }
}

Largest Rectangle in Histogram这题是找NLE和PLE,用increasing monotonic queue实现

class Solution {
    public int largestRectangleArea(int[] heights) {
        int max = 0;
        Stack s = new Stack<>();
        // 这里注意要把边界的bar给push进去方便处理
        for (int i = 0; i <= heights.length; i ++) {
            int h1 = i == heights.length ? 0 : heights[i];
            while (!s.isEmpty() && heights[s.peek()] > h1) { 
                int h2 = heights[s.pop()];
                int l = s.isEmpty() ? -1 : s.peek();
                max = Math.max(max, (i-l-1)*h2);
            }
            s.push(i);
        }
        return max;
    }
}

好处是不用担心左右两边重复计算的问题,但有时要考虑最后是否需要再push一个bar来处理最后一个数
码。
ps: 维护单调增区间:从尾部去掉比当前大的;维护单调减区间:从尾部去掉比当前小的

你可能感兴趣的:(leetcode)