当前位置:网站首页>单调栈-42. 接雨水
单调栈-42. 接雨水
2022-07-03 08:24:00 【later_rql】
1.题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/trapping-rain-water
2.解题思路
共有是三种方法解决:
方法一:双指针法

然后,当前列的雨水高度等于,min(LH,RH)-当前列高度。
特殊情况:第一列和最后以列不操作。
方法二:动态规划
其实是对双指针法的一种优化,因为在使用双指针法的时候,发现,在求每列的左右最大值的时候,存在着重复的计算,如果利用动态规划的方法记录。
即从左向右遍历:maxLeft[i] = max(height[i], maxLeft[i - 1]);
从右向左遍历:maxRight[i] = max(height[i], maxRight[i + 1]);
方法三:单调栈

分为三种情况:
(1)如果当前遍历的元素(柱子)高度小于栈顶元素的高度,就把这个元素加入栈中,因为栈里本来就要保持从小到大的顺序(从栈头到栈底)。
(2)如果当前遍历的元素(柱子)高度等于栈顶元素的高度,要跟更新栈顶元素,因为遇到相相同高度的柱子,需要使用最右边的柱子来计算宽度。
(3)如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了(这种情况会出现雨水)
其实质就是:栈顶和栈顶的下一个元素以及要入栈的三个元素来接水!

凹槽的高度:int h = min(height[st.top()], height[i]) - height[mid];
凹槽的宽度:int w = i - st.top() - 1 ;
凹槽的体积:h*w
3.代码
方法一:双指针法(非最优)
public int trap(int[] height) {
int sum = 0;
for (int i = 0; i < height.length; i++) {
// 第一个柱子和最后一个柱子不接雨水
if (i==0 || i== height.length - 1) continue;
int rHeight = height[i]; // 记录右边柱子的最高高度
int lHeight = height[i]; // 记录左边柱子的最高高度
for (int r = i+1; r < height.length; r++) {
if (height[r] > rHeight) rHeight = height[r];
}
for (int l = i-1; l >= 0; l--) {
if(height[l] > lHeight) lHeight = height[l];
}
int h = Math.min(lHeight, rHeight) - height[i];
if (h > 0) sum += h;
}
return sum;
}
方法二:动态规划
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;
}
方法三:单调栈法
public int trap(int[] height){
int size = height.length;
if (size <= 2) return 0;
// in the stack, we push the index of array
// using height[] to access the real height
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]){
// 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的index
stack.pop();
stack.push(index);
}else{
//pop up all lower value
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;
}
4.性能
方法一:双指针(非最优)
- 时间复杂度:O(n^2)
- 空间复杂度:O(l)
方法二:动态规划
- 时间复杂度:O(n)
- 空间复杂度:O(n)
方法三:单调栈
- 时间复杂度:O(n)
- 空间复杂度:O(n)
边栏推荐
猜你喜欢
随机推荐
Display terrain database on osgearth ball
CLion-Toolchains are not configured Configure Disable profile问题解决
About the problem that the editor and the white screen of the login interface cannot be found after the location of unityhub is changed
UE4 source code reading_ Mobile synchronization
Golang 中string和int类型相互转换
Redis data structure
【云原生】微服务之Feign的介绍与使用
jupyter远程服务器配置以及服务器开机自启
二进制转十进制,十进制转二进制
Unity editor expansion - window, sub window, menu, right-click menu (context menu)
Dotween plug-in
Unity4.3.1 engine source code compilation process
Unity learning notes
Unity editor expansion - controls, layouts
Conversion between golang JSON format and structure
VIM learning notes from introduction to silk skating
KunlunBase MeetUP 等您来!
ArrayList
Creation and content of mapnode -- osgearth rendering engine series (2)
Vscode, idea, VIM development tool shortcut keys









