算法——17.21、直方图的水量

求可以存储的水量,那么什么情况才能存到水呢?只有两头高,中间小的才能够存储到水,所以求能存储的水量的大
小,得先求得一共有多少的峰顶,然后根据峰顶的值来讨论,可能的情况如图所示

在这里插入图片描述

可以发现,对于前两种情况,能存多少水量由第一个峰值决定,而对于第三种情况,又会分为这么几种情况

在这里插入图片描述

对于第一行的情况来说,能存水量决定于第二块和第三块,分别是两个区间,对于第二行来说,存水量就决定于第三块
了,即大于第二块,但是小于第一块的情况,是一个区间,所以综合上面所有的情况就会得到:
	对于某一个峰值:
		当他后面存在大于他的峰值的时候,就将中间的储水量加起来
		当他后面的柱子都不大于他时,找到他后面的小于他的最大的那根柱子,求得中间水量
		之后从后面那个柱子开始,继续上述操作
	这样就可以得到最终的储水量了
class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0, i = 0, n = height.size() - 1;

		/*
			如果前面都是上升的,或者是平的地形,那么他是不可能储水的,去掉
		*/
        while(i + 1 < n && height[i] <= height[i + 1])
        {
            ++i;
        }
		/*
			对于后面的下降的或者是平的地形,也不能储水,也去掉
		*/
        while(n > 0 && height[n] <= height[n - 1])
        {
            --n;
        }

		/*
			当去掉前后之后,如果中间没有空位了,那就是两个峰值重合了,对应的就是一个尖尖的山,这种
			情况是不会有储水的,直接返回即可
		*/
        if(n - i <= 1)
        {
            return sum;
        }
        vector<int> temp;	// 用来存放峰值在原来地方的下标
        temp.push_back(i);	// 由于一开始先上了一次山,所以 i 处必然是一个峰值

		/*
			通过一次下山和一次上山得到下一个峰值点,并且存到temp中
		*/
        do
        {
            while(i + 1 <= n && height[i] >= height[i + 1])
            {
                ++i;
            }
            while(i + 1 <= n && height[i] <= height[i + 1])
            {
                ++i;
            }
            temp.push_back(i);
        }while(i + 1 <= n);

		/*
			l 用来保存还没有使用的左边的峰值,max 用来保存 他 右侧不大于自己的相对来说最大的那个峰值
			r 用来保存 max 这个峰值在 temp 中保存的位置,为了控制后面的下标 i 的循环跳转
		*/
		
        int l = temp[0], max = temp[1], r = 1;
        for(i = 1; i < temp.size(); ++i)
        {
			/*
				用于处理前面图示中的后面有大于当前峰值的柱子
			*/
            if(height[temp[i]] >= height[l])
            {
                for(int r = l + 1; r < temp[i]; ++r)
                {
                    if(height[l] - height[r] > 0)
                    {
                        sum += height[l] - height[r];
                    }
                }
                l = temp[i];
                if(i + 1 < temp.size())
                {
                    max = temp[i + 1];
                    r = i + 1;
                }
                continue;
            }

			/*
				用于处理前面的后面没有比他大的柱子的情况
			*/

            if(height[max] <= height[temp[i]])	// 不断的动态更新 max 的值
            {
                max = temp[i];
                r = i;
            }

			/*
				当 i 走到 temp 的最后一位还没有找到比当前大的柱子,那么就开始从当前 max 遍历,符合前面的
				图示的第三种情况的第二种情况。
			*/
			
            if(i == temp.size() - 1)
            {
                for(int r = l + 1; r < max; ++r)
                {
                    if(height[max] - height[r] > 0)
                    {
                        sum += height[max] - height[r];
                    }
                }
                i = r;
                l = max;
                if(i + 1 < temp.size())
                {
                    max = temp[i + 1];
                    r = i + 1;
                }
                else
                {
                    return sum;
                }
            }
        }
        
        return sum;
    }
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值