大家好我是魔笑,今天给大家带来的是用栈解决接雨水的算法题,我的题解,比较简洁明了,并且我用了两种代码方便大家理解,如果喜欢,请给一个点赞收藏哦,话不啰嗦,直入主题。
题目:
给定 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
示例3:
输入:height = [5,5,1,7,1,1,5,2,7,6]
输出:23
什么是栈?
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。有如下方法:
1 boolean empty()
判断栈是否为空。
2 Object peek( )
查看栈顶部的对象,但不从栈中移除它。
3 Object pop( )
移除栈顶部的对象,并作为此函数的值返回该对象。
4 Object push(Object element)
把元素压入栈顶部。
5 int search(Object element)
返回对象在栈中的位置,以 1 为基数。
题解:
首先当我们要求出接住雨水的面积,那么我们先看看什么情况下,才能接住雨水,那就是,两边高,中间低。
1,当我们遍历元素时,当后面的元素比前面的元素高是,那么舍弃前面的元素。
2,当下一个元素比上一个元素低时,那么我们就应该记录当前元素的位置,和高度。然后向前遍历,直到找到比记录的位置的元素高或者相等,那么就能记录出两者之间能接住雨水的面积。
3,以上面方式看,我们只能求出到从最左边到最高元素之间接住的雨水,之后的元素都比最高值小,所以,我们还得从反向遍历,求出从最右边到最高元素之间接住的雨水
我的最终简洁代码1:
**
* leetcode第42题,接雨水
*/
public class Trap {
//接住的雨水面积
private int maxArea = 0;
//记录元素的高度(它的下一个元素高度比它小)
private int maxHeight = 0;
//记录元素的下标(它的下一个元素高度比它小)
private int saveIndex = 0;
//最右边,最大的元素所在的下标
private int maxIndex = 0;
public int trapRain3(int[] height) {
int length = height.length;
//创建栈
Deque<Integer> stack = new LinkedList();
//查找从最左边起到最右边,最靠近右边的最大的元素所在的下标
stack.push(0);
for (int i = 0; i < length; i++) {
if (height[i] < height[stack.peek()]) {
continue;
}
stack.pop();
stack.push(i);
}
maxIndex = stack.peek();
//清空栈
stack.clear();
//求出从最左边到最大元素之间所能接住的雨水
for (int i = 0; i <= maxIndex; i++) {
calculateArea(height, stack, i, 1);
}
//清空栈
stack.clear();
maxHeight = 0;
//求出从最右边到最大元素之间所能接住的雨水
for (int i = length - 1; i >= maxIndex; i--) {
calculateArea(height, stack, i, -1);
}
return maxArea;
}
public void calculateArea(int[] height, Deque<Integer> stack, int i, int direction) {
//不满足要求雨水的条件时,当后面的元素比前面的元素高是,那么舍弃前面的元素
if (!stack.isEmpty() && height[i] >= stack.peek() && maxHeight == 0) {
stack.pop();
}
//如果下一个元素比上一个元素小,那么保存该元素的下标和值,
if (!stack.isEmpty() && height[i] < stack.peek() && maxHeight == 0) {
maxHeight = stack.peek();
saveIndex = i - 1 * direction;
}
//当元素比保存的元素的值大了,那么就计算从这个元素到之前保存的元素之间接住的雨水
if (height[i] >= maxHeight && maxHeight != 0) {
//把两者之间的面积都计算出来
maxArea = maxArea + Math.abs((saveIndex - i)) * maxHeight;
//然后去除两者之间的元素,就是接住的雨水
while (!stack.isEmpty()) {
maxArea = maxArea - stack.pop();
}
//状态重置,继续求接住雨水的面积
maxHeight = 0;
saveIndex = 0;
}
stack.push(height[i]);
}
}
如果上面的代码不好理解的话,下面的代码,可能会帮你更好的理解
易于理解代码2:
public static int trapRain2(int[] height) {
int length = height.length;
Deque<Integer> stack = new LinkedList();
//接住雨水的面积
int maxArea = 0;
//记录元素的高度(它的以一个元素高度比它小)
int maxHeight = 0;
//记录元素的下标(它的下一个元素高度比它小)
int saveIndex = 0;
最右边,最大的元素所在的下标
int maxIndex = 0;
//求出从最左边到最大元素之间接住的雨水
for (int i = 0; i <= length - 1; i++) {
if (!stack.isEmpty() && height[i] >= stack.peek() && maxHeight == 0) {
stack.pop();
}
//如果下一个元素比上一个元素小,那么保存该元素的下标和值,
if (!stack.isEmpty() && height[i] < stack.peek() && maxHeight == 0) {
maxHeight = stack.peek();
saveIndex = i - 1;
}
//当元素比保存的元素的值大了,那么就计算从这个元素到之前保存的元素之间接住的雨水
if (height[i] >= maxHeight && maxHeight != 0) {
maxArea = maxArea + Math.abs((saveIndex - i)) * maxHeight;
while (!stack.isEmpty()) {
maxArea = maxArea - stack.pop();
}
//状态重置
maxHeight = 0;
saveIndex = 0;
//记录下最高元素的下标
maxIndex = i;
}
stack.push(height[i]);
}
stack.clear();
maxHeight = 0;
//求出从最右边到最大元素之间接住的雨水
for (int i = length - 1; i >= maxIndex; i--) {
if (!stack.isEmpty() && height[i] >= stack.peek() && maxHeight == 0) {
stack.pop();
}
//如果下一个元素比上一个元素小,那么保存该元素的下标和值,
if (!stack.isEmpty() && height[i] < stack.peek() && maxHeight == 0) {
maxHeight = stack.peek();
saveIndex = i + 1;
}
//当元素比保存的元素的值大了,那么就计算从这个元素到之前保存的元素之间接住的雨水
if (height[i] > maxHeight && maxHeight != 0) {
maxArea = maxArea + Math.abs((saveIndex - i)) * maxHeight;
while (!stack.isEmpty()) {
maxArea = maxArea - stack.pop();
}
maxHeight = 0;
saveIndex = 0;
}
stack.push(height[i]);
}
return maxArea;
}
如果对大家有帮助请给一个素质三连把,谢谢。