LeetCode 407. 接雨水 II (优先队列)

参考 优先队列的思路解决接雨水II,逐行解释

 

从最外圈开始不断向内遍历,如果内部的高度小于外部的高度,则证明该位置可以蓄水,否则不能,水会顺着该外圈流出去。

每次都处理外圈高度最小的那个位置 a,遍历它的四周。

如果它旁边的某个位置 b 高度小于 a,则证明 b 可以蓄水,因为 a 已经是四周最小的高度了,则 b 可以蓄水的大小就是  height(a)-height(b) 

如果 b 的高度大于 a 则不能蓄水,水会顺着 a 流出去。

处理完 a 周围的所有位置后,把 a 删除,把 a 周围的位置当做新的边界。

其中,如果 a 周围的高度有小于 a 的,就补齐到 a,因为其是被 a 围住的,注水时高度不可能小 a。而如果高度大于 a 不用处理。

 

具体实现,先把最外圈的所有高度压入优先队列,然后每次取高度最小的去处理就可以了。

 

理解了还是觉得有点抽象。有一说一。其他题解一个都没看懂。

 

struct node {
    int x, y, h;
    node() {}
    node(int x, int y, int h): x(x), y(y), h(h) {}
    bool operator<(const node &rhs) const {
        return h > rhs.h; // 保证优先队列是小顶堆
    }
};

class Solution {
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        priority_queue<node> q;
        int n = heightMap.size(), m = heightMap[0].size();
        vector<vector<int>> visited(n, vector<int>(m, 0));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (i == 0 || j == 0 || i == n - 1 || j == m - 1) {
                    q.emplace(i, j, heightMap[i][j]);
                    visited[i][j] = 1;
                }
            }
        }
        int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        int ans = 0;
        while (q.size()) {
            node cur = q.top(); q.pop();
            for (int i = 0; i < 4; i++) {
                int nx = cur.x + dir[i][0];
                int ny = cur.y + dir[i][1];
                if (nx < n && nx >= 0 && ny < m && ny >= 0 && !visited[nx][ny]) {
                    if (heightMap[nx][ny] < cur.h) {
                        ans += cur.h -  heightMap[nx][ny];
                        q.emplace(nx, ny, cur.h);
                    } else {
                        q.emplace(nx, ny, heightMap[nx][ny]);
                    }
                    visited[nx][ny] = 1;
                }
            }
        }
        return ans;
    }
};

 

 

posted @ 2021-12-12 17:06  我不吃饼干呀  阅读(117)  评论(0编辑  收藏  举报