单调栈章节理论基础:
https://leetcode.cn/problems/daily-temperatures/
739. 每日温度
题目链接:https://leetcode.cn/problems/daily-temperatures/
思路:
这道题和739. 每日温度 也几乎如出一辙。不过,本题要循环数组了。
有的人看到这道题,就想那我直接把两个数组拼接在一起,然后使用单调栈求下一个最大值不就行了。确实可以,将两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即result数组resize到原数组大小就可以了。
这种写法确实比较直观,但做了很多无用操作,例如修改了nums数组,而且最后还要把result数组resize回去。
resize倒是不费时间,是O(1)的操作,但扩充nums数组相当于多了一个O(n)的操作。
其实也可以不扩充nums,而是在遍历的过程中模拟走了两遍nums就行了。
代码:
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] res = new int[n];
Arrays.fill(res,-1);
Stack<Integer>stack = new Stack<>();
stack.push(0);
// 循环数组 《=》 模拟遍历两遍数组
for(int i=1;i<2*n;i++){
// if(nums[stack.peek()] >= nums[i % n]){
// stack.push(i % n);
// }else{
while(!stack.isEmpty() && nums[stack.peek()] < nums[i % n]){
res[stack.peek()] = nums[i % n];
stack.pop();
}
stack.push(i % n);
// }
}
return res;
}
}
42. 接雨水
题目链接:https://leetcode.cn/problems/trapping-rain-water/
思路:
首先要明确,要按照行来计算,还是按照列来计算。
如果按照列来计算的话,宽度一定是1了,我们再把每一列的雨水的高度求出来就可以了。
可以看出每一列雨水的高度,取决于,该列 左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。
例如求列4的雨水高度,如图:
列4 左侧最高的柱子是列3,高度为2(以下用lHeight表示)。
列4 右侧最高的柱子是列7,高度为3(以下用rHeight表示)。
列4 柱子的高度为1(以下用height表示)
那么列4的雨水高度为 列3和列7的高度最小值减列4高度,即: min(lHeight, rHeight) - height。
列4的雨水高度求出来了,宽度为1,相乘就是列4的雨水体积了。此时求出了列4的雨水体积。
一样的方法,只要从头遍历一遍所有的列,然后求出每一列雨水的体积,相加之后就是总雨水的体积了。
首先从头遍历所有的列,并且要注意第一个柱子和最后一个柱子不接雨水。
代码:
class Solution {
public int trap(int[] height) {
int n = height.length;
int[] leftBigger = new int[n];
int[] rightBigger = new int[n];
leftBigger[0] = height[0];
// 双指针解法
for(int i=1;i<n;i++){
leftBigger[i] = Math.max(height[i],leftBigger[i-1]);
}
rightBigger[n-1] = height[n-1];
for(int i=n-2;i>=1;i--){
rightBigger[i] = Math.max(height[i],rightBigger[i+1]);
}
// for(int i=0;i<n;i++){
// System.out.print(leftBigger[i] + " ");
// }
// System.out.println();
// for(int i=0;i<n;i++){
// System.out.print(rightBigger[i] + " ");
// }
int res = 0;
for(int i=1;i<n-1;i++){
res += Math.min(rightBigger[i],leftBigger[i]) - height[i];
}
return res;
}
}