文章目录
- 前言
- 一、503.下一个更大元素II
- 二、42. 接雨水
- 总结
前言
单调栈;
一、503.下一个更大元素II
循环的问题:1.多建立一个数组 2.采用取模的方法;
问题:采用取模,后面的值会被前面的覆盖掉吗?
答:不会,因为采用的单调栈是递增的,所以大的数值会在栈中被保留下去。
下面的是简略版,>= 的情况没有用if表示出来:
class Solution {
public int[] nextGreaterElements(int[] nums) {
if(nums == null || nums.length <=1){
return new int[]{-1};
}
int size = nums.length;
int[] result = new int[size];
Arrays.fill(result,-1);
Stack<Integer> st = new Stack<>();
for(int i =0;i<2*size;i++){
while(!st.empty() && nums[i%size] > nums[st.peek()]){
result[st.peek()] = nums[i%size];
st.pop();
}
st.push(i%size);
}
return result;
}
}
二、42.接雨水
当前列雨水面积:min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。
三种解法:1. 暴力 2. 双指针 3. 单调栈
1.暴力:
按照列来计算如图:
首先,如果按照列来计算的话,宽度一定是1了,我们再把每一列的雨水的高度求出来就可以了。从头遍历所有的列,并且要注意第一个柱子和最后一个柱子不接雨水;
2.双指针:
为了得到两边的最高高度,使用了双指针来遍历,每到一个柱子都向两边遍历一遍,这其实是有重复计算的。我们把每一个位置的左边最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight),这样就避免了重复计算。
即从左向右遍历:maxLeft[i] = max(height[i], maxLeft[i - 1]);
从右向左遍历:maxRight[i] = max(height[i], maxRight[i + 1]);
3.单调栈:
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。
- 首先单调栈是按照行方向来计算雨水,如图:
知道这一点,后面的就可以理解了。
- 使用单调栈内元素的顺序
从大到小还是从小到大呢?
从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。
- 遇到相同高度的柱子怎么办。
遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。例如 5 5 1 3 这种情况。如果添加第二个5的时候就应该将第一个5的下标弹出,把第二个5添加到栈中。因为我们要求宽度的时候 如果遇到相同高度的柱子,需要使用最右边的柱子来计算宽度。
栈里要保存什么数值
stack<int> st; // 存着下标,计算的时候用下标对应的柱子高度
双指针:
class Solution {
public int trap(int[] height) {
int length = height.length;
if(length <= 2) return 0;
int[] maxLeft = new int[length];
int[] maxRight = new int[length];
maxLeft[0] = height[0];
for(int i = 1;i<length;i++){
maxLeft[i] = Math.max(height[i],maxLeft[i-1]);
}
maxRight[length-1] = height[length-1];
for(int i = length-2;i>=0;i--){
maxRight[i] = Math.max(height[i],maxRight[i+1]);
}
int sum = 0;
for(int i = 0;i<length;i++){
int count = Math.min(maxLeft[i],maxRight[i]) - height[i];
if(count > 0) sum += count;
}
return sum;
}
}
单调栈:
class Solution{
public int trap(int[] height){
int size = height.length;
if(size <= 2) return 0;
Stack<Integer> stack = new Stack<Integer>();
stack.push(0);
int sum = 0;
for(int index = 1;index < size;index++){
int stackTop = stack.peek();
if(height[index] < height[stackTop]){
stack.push(index);
}else if(height[index] == height[stackTop]){
stack.pop();
stack.push(index);
}else{
int heightAtIdx = height[index];
while(!stack.isEmpty() && (heightAtIdx > height[stackTop])){
int mid= stack.pop();
if(!stack.isEmpty()){
int left = stack.peek();
int h = Math.min(height[left],height[index]) - height[mid];
int w = index -left-1;
int hold = h*w;
if(hold > 0) sum += hold;
stackTop = stack.peek();
}
}
stack.push(index);
}
}
return sum;
}
}
总结
单调栈;