84、柱状图中最大的矩形
解法:单调栈
从左到右列出各高度的左边界数组,从右到左列出右边界数组,利用公式ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);得出答案。
左边界数组的求解方法:
我们遍历每个柱体高度,若当前的柱体高度大于等于栈顶柱体的高度,就直接将当前柱体入栈,否则若当前的柱体高度小于栈顶柱体的高度,说明当前栈顶柱体找到了右边的第一个小于自身的柱体,那么就可以将栈顶柱体出栈来计算以其为高的矩形的面积了。
left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());//左边界等于栈顶
右边界反过来计算一样的。right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Stack<Integer> mono_stack = new Stack<Integer>();
for (int i = 0; i < n; ++i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
mono_stack.pop();
}
left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
mono_stack.push(i);
}
mono_stack.clear();
for (int i = n - 1; i >= 0; --i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
mono_stack.pop();
}
right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
mono_stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}
单调栈 + 常数优化解法:
i左边界的思路一样:left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());//当i元素<栈顶元素时,i的左边界等于栈顶
可以确定的不是i的右边界,是栈顶的右边界:right[mono_stack.peek()] = i;//当i元素<栈顶元素时,栈顶顶右边界等于i
面积:ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Arrays.fill(right, n);
Stack<Integer> mono_stack = new Stack<Integer>();
for (int i = 0; i < n; ++i) {
while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
right[mono_stack.peek()] = i;
mono_stack.pop();
}
left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
mono_stack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
}
739、每日温度
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
解题:单调栈
依次入栈,栈顶为T[prevIndex],若该元素T[i]<T[prevIndex],入栈;若T[i]>T[prevIndex],依次返回i - prevIndex,并且栈顶元素出栈。
例子,对于温度列表 [73,74,75,71,69,72,76,73],答案 ansans 的初始状态是 [0,0,0,0,0,0,0,0],
class Solution {
public int[] dailyTemperatures(int[] T) {
int length = T.length;
int[] ans = new int[length];
Deque<Integer> stack = new LinkedList<Integer>();
for (int i = 0; i < length; i++) {
int temperature = T[i];
while (!stack.isEmpty() && temperature > T[stack.peek()]) {
int prevIndex = stack.pop();
ans[prevIndex] = i - prevIndex;
}
stack.push(i);
}
return ans;
}
}
给定两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
解题:单调栈
先不管nums1,先对将 nums2 中的每一个元素,求出其下一个更大的元素。
随后对于将这些答案放入哈希映射(HashMap)中,当nums[i] > stack.peek(),实现哈希映射map.put(stack.pop(), nums[i]);将i元素入栈stack.push(nums[i])。
再遍历数组 nums1,并直接找出答案。对于 nums2,我们可以使用单调栈来解决这个问题。
public class Solution {
public int[] nextGreaterElement(int[] findNums, int[] nums) {
Stack < Integer > stack = new Stack < > ();
HashMap < Integer, Integer > map = new HashMap < > ();
int[] res = new int[findNums.length];
for (int i = 0; i < nums.length; i++) {
while (!stack.empty() && nums[i] > stack.peek())
map.put(stack.pop(), nums[i]);
stack.push(nums[i]);
}
while (!stack.empty())
map.put(stack.pop(), -1);
for (int i = 0; i < findNums.length; i++) {
res[i] = map.get(findNums[i]);
}
return res;
}
}
42.接雨水
解题:单调栈
public int trap(int[] height) {
int ans = 0, current = 0;
Deque<Integer> stack = new LinkedList<Integer>();
while (current < height.length) {
while (!stack.isEmpty() && height[current] > height[stack.peek()]) {
int top = stack.pop();
if (stack.isEmpty())
break;
int distance = current - stack.peek() - 1;
int bounded_height = Math.min(height[current], height[stack.peek()]) - height[top];
ans += distance * bounded_height;
}
stack.push(current++);
}
return ans;
}