LC 42. Trapping Rain Water 双指针 求能收集的最多的水的体积

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

For example, 

Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

思路:找到数组中最大的数,它的值为maxHeight,它对应的下标为maxHeightIndex。在这个最大值的左右两边运用双指针分别计算可以trap的最多水的体积。考虑下面这个情况,输入的test case为数组[2,1,3,0,5,1,2,4],所以maxHeight = 5,maxHeightIndex = 4. 怎么计算5左边能容纳的水的体积呢?

考虑 0 <= index1 < index2 <maxHeightIndex,其中 height[index1] > height[index2]。为了计算index2处可以容纳的水的体积,需要知道水的高度。因为maxHeightIndex在右边,它对应着最高的柱子,所以只要考虑左侧index1的高度就能确定index2处的最大高度。换言之,从index2的角度看,只要关心index2左边最高的柱子就可以了额,因为右边总能满足“兜住水”的要求。因此指针从index = 0开始从左向右遍历,不断维护最高的柱子,并且边遍历边计算当前index可以容纳的水柱高度。代码如下:

int trap(vector<int>& height) {
    if (height.size() <= 2) {
        return 0;
    }
    int i, maxHeight, maxHeightIndex;
    maxHeight = maxHeightIndex =  0;
    for (i = 0; i < height.size(); i++) {
        if(height[i] > maxHeight) {
            maxHeightIndex = i;
            maxHeight = height[i];
        }
    }
    int root = height[0], res = 0;
    for (i = 0; i < maxHeightIndex; i++) {
        if (height[i] > root) {
            root = height[i];
        }
        else {
            res += (root - height[i]);
        }
    }
    root = height[height.size() - 1];
    for (i = (int)height.size() - 1; i > maxHeightIndex; i--) {
        if (height[i] > root) {
            root = height[i];
        }
        else {
            res += (root - height[i]);
        }
    }
    return res;
}

代码核心的地方就是

 if (height[i] > root) {
            root = height[i];
        }
        else {
            res += (root - height[i]);
        }

其含义就是维护一个最高的柱子root,并且如果当前柱子低于最高的柱子就把 res+= 当前柱子可以容纳的水的体积。

这道题的难度为Hard,但是感觉做下来并不是很难。很多双指针的题目都依赖于一种对问题分析后产生的规律性的判断或者结论,有了它问题就得到了简化,带来的进步就是获得最优解所需要判断的case少了很多,复杂度就下降了一个级别(O(n*n) -> O(n))。例如这里的总结就是最高柱子两旁任意处能容纳的水柱高度取决于其外侧最高柱子的高度。在另外一个求水体积的题目中(11. Container With Most Water),规律就是在底边长变短的情况下唯有高变长才有可能产生一个更大体积,所以先将底边长放到最长,然后逐渐向中间收缩,因为更大的体积只有可能来源于这个过程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值