LeetCode每日一题(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 can trap after raining.

Example 1:

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.

Example 2:

Input: height = [4,2,0,3,2,5]
Output: 9

Constraints:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

以前做过, 但是可能添加了新的测试用例, 原来的代码再提交就超时了。 所以重新做一遍。

比较难表达, 自己也是做了挺久才做出来, 整体思路其实就是维持一个单调递减的队列, 如果当前 bar 的高度高于队尾 bar 的高度, 我们要从队尾向前进行 merge 操作, 其实就是将当前 bar 之前所有低于当前 bar 的所有 bar 补齐到当前 bar 的高度,所补齐的这些方块就是所蓄的水, 要加到答案中, 之后我们可以将这些被补齐的 bar 看做是一个整体,高度与当前 bar 相等, 宽度我们在 merge 的过程中累计得到, 然后我们将该"宽"bar 放到队尾即完成一次操作。整个过程中要注意的是,如果当前 bar 比队首的 bar 还要高, 则证明当前 bar 比队列里任何一个 bar 都要高,此时计算的时候不能简单的用当前 bar 与前面 bar 的高度差进行计算, 要采用队首的 bar 的高度与前面 bar 的高度差进行计算, 因为一个“桶”所能盛水的高度取决与左右两边“桶壁”的最小高度。


impl Solution {
    pub fn trap(height: Vec<i32>) -> i32 {
        let mut queue = Vec::new();
        let mut ans = 0;
        'outer: for h in height {
            if queue.is_empty() {
                queue.push((h, 1));
                continue;
            }
            let (first_h, _) = queue.first().unwrap().clone();
            let (last_h, _) = queue.last().unwrap().clone();
            if last_h > h {
                queue.push((h, 1));
                continue;
            }
            if last_h == h {
                queue.last_mut().unwrap().1 += 1;
                continue;
            }
            if first_h > h {
                let mut width = 1;
                while let Some((prev_h, prev_w)) = queue.pop() {
                    if prev_h > h {
                        queue.push((prev_h, prev_w));
                        queue.push((h, width));
                        continue 'outer;
                    }
                    if prev_h == h {
                        queue.push((prev_h, prev_w + width));
                        continue 'outer;
                    }
                    width += prev_w;
                    ans += (h - prev_h) * prev_w;
                }
            }
            if first_h <= h {
                while let Some((prev_h, prev_w)) = queue.pop() {
                    ans += (first_h - prev_h) * prev_w;
                }
                queue.push((h, 1));
            }
        }
        ans
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值