精选leetCode得42题接雨水(栈)

大家好我是魔笑,今天给大家带来的是用栈解决接雨水的算法题,我的题解,比较简洁明了,并且我用了两种代码方便大家理解,如果喜欢,请给一个点赞收藏哦,话不啰嗦,直入主题。

题目:

给定 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;
    }

如果对大家有帮助请给一个素质三连把,谢谢。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值