很不擅长的一部分内容,值得总结一下
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<Integer> 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<Integer> 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<Integer> 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<Integer> 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: 维护单调增区间:从尾部去掉比当前大的;维护单调减区间:从尾部去掉比当前小的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。