面试题 17.21. 直方图的水量

这篇博客介绍了如何利用双指针法和单调栈解决计算机科学中的一个经典问题——计算直方图能储存的水量。通过分析直方图的特性,提出两种不同的算法实现,一种是双指针法,另一种是单调栈方法,有效地找出每个位置能形成的水容量,并最终求和得到总储水量。示例中给出了具体的代码实现和解释,适用于提升编程和算法理解能力。
摘要由CSDN通过智能技术生成

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

在这里插入图片描述

上面是由数组 [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

解答

位置i处的水量由左右两侧最高处其中的较小值决定,因此可以使用双指针法,此外记录left指针左侧的最大值left_max,以及right指针右侧的最大值right_max

class Solution {
public:
    int trap(vector<int>& height) {
        if(height.empty())
            return 0;
        int left = 0, right = height.size() - 1;
        int left_max = 0, right_max = 0;
        int result = 0;
        while(left < right){
            left_max = max(left_max, height[left]);
            right_max = max(right_max, height[right]);
            // 由左边的短板决定
            if(height[left] < height[right]){
                result += (left_max - height[left]);
                left++;
            }
            // 由右边的短板决定
            else{
                result += (right_max - height[right]);
                right--;
            }
        }
        return result;
    }
};

单调栈,存储位置索引,从栈底到栈顶高度依次递减,从左到右遍历,每遍历到一个比栈顶高的元素,就说明可以以栈顶元素为底,栈顶下一个元素(单调栈,一定是左侧更高的位置)和当前遍历元素为左右边界,构成一个可以盛水的矩形:

class Solution {
public:
    int trap(vector<int>& height) {
        if(height.empty())
            return 0;
        stack<int> s;
        int result = 0;
        for(int i = 0; i < height.size(); i++){
            while(!s.empty() && height[s.top()] < height[i]){
                int mid = s.top();
                s.pop();
                if(s.empty())
                    break;
                int left = s.top();
                int w = i - left - 1;
                int h = min(height[i], height[left]) - height[mid];
                result += (w * h);

            }
            s.push(i);
        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值