单调栈的整体的运用范围: 要保留遍历过元素的状态的时候。
问题1:每日温度
题目:
https://leetcode.cn/problems/daily-temperatures/description/
思路:
最关键的问题:是啥单调栈 递增还是递减
这个如何判断呢 就是看我要比较的 比如说我拿到一个温度 我要去看看 之后比他高的温度对吧 所以啥 应该放递增栈
代码:
java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
Deque<Integer> stack = new LinkedList<>();
int res[] = new int[temperatures.length];
stack.push(0);
for(int i = 1; i < temperatures.length; i++){
// 循环对比
while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
res[stack.peek()] = i - stack.peek();
stack.pop();
}
// 如果是空的话 那就添加
stack.push(i);
}
return res;
}
}
问题2:下一个更大的元素I
题目:
https://leetcode.cn/problems/next-greater-element-i/
思路:
在问题1的基础上加了一个映射
代码:
java
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Deque<Integer> stack = new LinkedList<>();
int res[] = new int[nums1.length];
// 借用hashmap存放nums[1]的映射
HashMap<Integer,Integer> map = new HashMap<>();
for(int i = 0; i < nums1.length; i++) res[i] = -1;
for(int i = 0; i < nums1.length; i++) map.put(nums1[i],i);
stack.push(0);
for(int i = 1; i < nums2.length; i++){
while(!stack.isEmpty() && nums2[stack.peek()] < nums2[i]){
if(!map.containsKey(nums2[stack.peek()])){
stack.pop();
}else{
res[map.get(nums2[stack.peek()])] = nums2[i];
stack.pop();
}
}
stack.push(i);
}
return res;
}
}
问题3:下一个更大的元素II
题目:
https://leetcode.cn/problems/next-greater-element-ii/description/
思路:
在问题2的基础之上 加了个循环的条件 遇见循环考虑用nums[i%len] 一个新的思路
代码:
java
class Solution {
public int[] nextGreaterElements(int[] nums) {
Deque<Integer> stack = new LinkedList<>();
int len = nums.length;
int res[] = new int [len];
for(int i = 0; i < len; i++) res[i] = -1;
stack.push(0);
for(int i = 1; i < len*2; i++){
while(!stack.isEmpty() && nums[stack.peek()] < nums[i%len]){
res[stack.peek()] = nums[i%len];
stack.pop();
}
stack.push(i%len);
}
return res;
}
}
问题4:接雨水
题目:
https://leetcode.cn/problems/trapping-rain-water/description/
思路:
在前三道题的基础之上 这里维护的是一个区间
left
right
mid
弄清楚这三个
代码:
java
class Solution {
public int trap(int[] height) {
if(height.length <=2){
return 0;
}
Stack<Integer> stack = new Stack<>();
int res = 0;
stack.push(0);
for(int i = 1; i < height.length; i++){
if(height[i] < height[stack.peek()]){
stack.push(i);
}else if(height[i] == height[stack.peek()]){
// 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的index
stack.pop();
stack.push(i);
}else{
while(!stack.isEmpty() && height[i] > height[stack.peek()]){
// 先记录中间的 把移动放到上面
int mid = stack.pop();
if(!stack.isEmpty()){
int h = Math.min(height[i],height[stack.peek()])-height[mid];
int w = i - stack.peek()-1;
res += (h*w);
}
}
stack.push(i);
}
}
return res;
}
}
问题5:柱状图中的最大的矩形
题目:
https://leetcode.cn/problems/largest-rectangle-in-histogram/description/
思路:
在前三道题的基础之上 这里维护的是一个区间
left
right
mid
弄清楚这三个
其中这里的是单调递减栈
代码:
java
class Solution {
public int largestRectangleArea(int[] heights) {
if(heights.length == 0){
return 0;
}
// 增加哨兵
int[] newheight = new int [heights.length + 2];
newheight[0] = 0;
newheight[heights.length + 1] = 0;
for(int i = 0; i < heights.length; i++){
newheight[i+1] = heights[i];
}
// 单调栈的模版题
Deque<Integer> stack = new LinkedList<>();
int maxArea = 0;
stack.push(0);
for(int i = 0; i < newheight.length; i++){
if(newheight[i] > newheight[stack.peek()]){
stack.push(i);
}else if(newheight[i] == newheight[stack.peek()]){
stack.pop();
stack.push(i);
}else{
while(!stack.isEmpty() && newheight[i] < newheight[stack.peek()]){
int mid = stack.peek();
stack.pop();
if(!stack.isEmpty()){
int left = stack.peek();
int right= i;
int h = newheight[mid];
int w = right - left -1;
maxArea = Math.max(maxArea,h*w);
}
}
stack.push(i);
}
}
return maxArea;
}
}