LeetCode 面试题 17.21. 直方图的水量 双指针,单调栈/hard

本文介绍了如何解决柱状图储水问题,提供了两种算法思路:双指针和单调栈。双指针方法通过从两端向中间遍历,计算每个位置的最大储水量。单调栈方法利用栈来存储下标,保证栈内下标对应的柱子高度递减,从而计算出每个位置的储水量。这两种方法都能有效地计算出直方图能储存的水量。
摘要由CSDN通过智能技术生成


1.Description

给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。


2.Example

在这里插入图片描述
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的直方图,在这种情况下,可以接 6 个单位的水(蓝色部分表示水)。 感谢 Marcos 贡献此图。

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

3.Solution

1.双指针

定义两个指针分别从左右两边往中间遍历,遍历的过程中保存最高点并且加上水量。
当时自己写的时候没有加上代码中加注释的那一个if条件,导致错误,要注意。

参考:添加链接描述

class Solution {
    public static int trap(int[] height) {
        int N = height.length;
        if(N<2) {
        	return 0;
        }
        int left=0,right = N-1;
        int lHeight = 0,rHeight = 0;
        int res = 0;
        while(left<right) {
        	//这里的条件是:当右边比左边高时计算左边的水量,左边比右边高时计算右边的水量,
        	//即计算左边的水量时保证右边一定有一个比左边高的墙能与左边形成一个坑,否则将无法计算水量;右边也是同理。
        	if(height[left]<height[right]) {
        		if(height[left]<lHeight) {
        			res += lHeight - height[left];
        		}else {
        			lHeight = height[left];
        		}
        		left++;
        	}else {
        		if(height[right]<rHeight) {
        			res += rHeight - height[right];
        		}else {
        			rHeight = height[right];
        		}
        		right--;
        	}
        }
        return res;
    }
}

2.单调栈

维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组height 中的元素递减。

从左到右遍历数组,遍历到下标i时,如果栈内至少有两个元素,记栈顶元素为top,top的下面一个元素是left,则一定有height[(left > height(top]。如果height[i]> height)top),则得到一个可以接雨水的区域,该区域的宽度是i- left-1,高度是min(height[left , heightji]) - height(top],根据宽度和高度即可计算得到该区域能接的水的量。

为了得到left,需要将top出栈。在对 top计算能接的水的量之后,left变成新的top,重复上述操作,直到栈变为空,或者栈顶下标对应的height中的元素大于或等于height[i]。

在对下标i处计算能接的水的量之后,将i入栈,继续遍历后面的下标,计算能接的水的量。遍历结束之后即可得到能接的水的总量。

动图见官方题解:添加链接描述

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        Deque<Integer> stack = new LinkedList<Integer>();
        int n = height.length;
        for (int i = 0; i < n; ++i) {
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                int top = stack.pop();
                if (stack.isEmpty()) {
                    break;
                }
                int left = stack.peek();
                int currWidth = i - left - 1;
                int currHeight = Math.min(height[left], height[i]) - height[top];
                ans += currWidth * currHeight;
            }
            stack.push(i);
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值