407. Trapping Rain Water II

https://leetcode.com/problems/trapping-rain-water-ii/

往高低不平的一堆相连的方柱注水,问最多能保持住多少水。是之前Trapping Rain Water I拓展到二维的情况,但解法并不只是对每个格子横竖都检查一遍就可以了,因为(i, j)能蓄多少水取决于j列能蓄多少水,而j列能蓄多少又取决于([0, i -1], j),相互之间形成了dependency。虽然不能直接套用一维的解法,但基本原则是一样的:1. 每块能蓄多少水是由它(即使隔的很远)最高的一圈外围决定的;2. 又取决于那圈外围中最矮的高度。因此模拟不断增加高度从外往内漫水的过程,从最外层开始做BFS,维持一个global变量记录当前遍历过的最高高度mx。每次找Q中高度最小的块抛出并更新最高高度mx,模拟水位到了mx的情况,mx也就是外围中最矮高度。遍历它前后左右并压入Q做候选,如果邻居中找到了比当前块还低的块,意味着水位mx - height(neighbor)就是neighbor能蓄的水量。

/*
 * @lc app=leetcode id=407 lang=cpp
 *
 * [407] Trapping Rain Water II
 */

// @lc code=start
class Solution {
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        if (heightMap.empty()) return 0;
        const int M = heightMap.size(), N = heightMap[0].size();
        // min heap
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
        vector<vector<bool>> visited(M, vector<bool>(N, false));
        vector<vector<int>> dirs{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        for (int i = 0; i < M; ++i) {
            for (int j = 0; j < N; ++j) {
                if (i == 0 || i == M - 1 || j == 0 || j == N - 1) {
                    q.push({heightMap[i][j], i * N + j});
                    visited[i][j] = true;
                }
            }
        }
        int mx = 0, res = 0;
        while (!q.empty()) {
            const auto t = q.top(); q.pop();
            const auto h = t.first, i = t.second / N, j = t.second % N;
            mx = max(mx, h);
            for (const auto &d : dirs) {
                const int x = i + d[0], y = j + d[1];
                if (x >= 0 && x < M && y >= 0 && y < N && !visited[x][y]) {
                    visited[x][y] = true;
                    if (heightMap[x][y] < mx) res += mx - heightMap[x][y];
                    q.push({heightMap[x][y], x * N + y});
                }
            }
        }
        return res;
    }
};
// @lc code=end

Last updated