407. Trapping Rain Water II

/*
 *  自己写的,通过32/40个case,TLE错误!
*/
struct pos {
    int x;
    int y;
    int height;
};

class posGreaterCmp {
    public:
        bool operator ()(const pos &p1,const pos &p2) const {
            return p1.height>p2.height;
        }
};

class posSort {
    public:
        bool operator ()(const pos &p1,const pos &p2) const {
            if(p1.x!=p2.x)
                return p1.x<p2.x;
            else
                return p1.y<p2.y;
        }
};

class Solution {
    public:
        int trapRainWater(vector<vector<int> >& heightMap) {
            if (heightMap.size()==0||heightMap[0].size()==0)
                return 0;
            priority_queue< pos,vector<pos>,posGreaterCmp >priq;
            int row=heightMap.size();
            int col=heightMap[0].size();
            for (int i=1; i<row-1; ++i)
                for (int j=1; j<col-1; ++j) {
                    priq.push({i,j,heightMap[i][j]});
                }

            int trapWater=0;
            while(!priq.empty()) {
                pos searchPos=priq.top();
                priq.pop();
                if (searchPos.height==heightMap[searchPos.x][searchPos.y]) {
                    set<pos,posSort>visitedSet;
                    queue<pos>temq;
                    temq.push(searchPos);
                    int flag=0;
                    int dir[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};
                    int minHeight=INT_MAX;

                    while(!temq.empty()) {
                        pos ps=temq.front();
                        temq.pop();
                        visitedSet.insert(ps);
                        for (int i=0; i<4; ++i)
                            for (int j=0; j<2; ++j) {
                                int px=ps.x+dir[i][0];
                                int py=ps.y+dir[i][1];
                                pos nextPos= {px,py,heightMap[px][py]};
                                if (visitedSet.count(nextPos)==0) {
                                    if (nextPos.height<ps.height||nextPos.height==ps.height&&(nextPos.x==0||nextPos.x==row-1||nextPos.y==0||nextPos.y==col-1)) {
                                        flag=1;
                                        break;
                                    } else if (nextPos.height==ps.height) {
                                        temq.push(nextPos);
                                    } else if (nextPos.height>ps.height)
                                        minHeight=min(minHeight,nextPos.height);
                                }
                            }
                        if (flag)
                            break;
                    }
                    if (!flag) {
                        trapWater+=(minHeight-searchPos.height)*visitedSet.size();
                        set<pos,posSort>::iterator it;
                        for (it=visitedSet.begin(); it!=visitedSet.end(); ++it) {
                            heightMap[it->x][it->y]=minHeight;
                        }
                        priq.push({searchPos.x,searchPos.y,minHeight});
                    }
                }
            }
            return trapWater;
        }
};

这道题是之前那道Trapping Rain Water的拓展,由2D变3D了,感觉很叼。但其实解法跟之前的完全不同了,之前那道题由于是二维的,我们可以用双指针来做,而这道三维的,我们需要用BFS来做,解法思路很巧妙,下面我们就以题目中的例子来进行分析讲解,多图预警,手机流量党慎入:

首先我们应该能分析出,能装水的底面肯定不能在边界上,因为边界上的点无法封闭,那么所有边界上的点都可以加入queue,当作BFS的启动点,同时我们需要一个二维数组来标记访问过的点,访问过的点我们用红色来表示,那么如下图所示:

我们再想想,怎么样可以成功的装进去水呢,是不是周围的高度都应该比当前的高度高,形成一个凹槽才能装水,而且装水量取决于周围最小的那个高度,有点像木桶原理的感觉,那么为了模拟这种方法,我们采用模拟海平面上升的方法来做,我们维护一个海平面高度mx,初始化为最小值,从1开始往上升,那么我们BFS遍历的时候就需要从高度最小的格子开始遍历,那么我们的queue就不能使用普通队列了,而是使用优先级队列,将高度小的放在队首,最先取出,这样我们就可以遍历高度为1的三个格子,用绿色标记出来了,如下图所示:

向周围BFS搜索的条件是不能越界,且周围格子未被访问,那么可以看出上面的第一个和最后一个绿格子无法进行进一步搜索,只有第一行中间那个绿格子可以搜索,其周围有一个灰格子未被访问过,将其加入优先队列queue中,然后标记为红色,如下图所示:

那么优先队列queue中高度为1的格子遍历完了,此时海平面上升1,变为2,此时我们遍历优先队列queue中高度为2的格子,有3个,如下图绿色标记所示:

我们发现这三个绿格子周围的格子均已被访问过了,所以不做任何操作,海平面继续上升,变为4,遍历所有高度为4的格子,如下图绿色标记所示:

由于我们没有特别声明高度相同的格子在优先队列queue中的顺序,所以应该是随机的,其实谁先遍历到都一样,对结果没啥影响,我们就假设第一行的两个绿格子先遍历到,那么那么周围各有一个灰格子可以遍历,这两个灰格子比海平面低了,可以存水了,把存水量算出来加入结果res中,如下图所示:

上图中这两个遍历到的蓝格子会被加入优先队列queue中,由于它们的高度小,所以下一次从优先队列queue中取格子时,它们会被优先遍历到,那么左边的那个蓝格子进行BFS搜索,就会遍历到其左边的那个灰格子,由于其高度小于海平面,也可以存水,将存水量算出来加入结果res中,如下图所示:

等两个绿格子遍历结束了,它们会被标记为红色,蓝格子遍历会先被标记红色,然后加入优先队列queue中,由于其周围格子全变成红色了,所有不会有任何操作,如下图所示:

此时所有的格子都标记为红色了,海平面继续上升,继续遍历完优先队列queue中的格子,不过已经不会对结果有任何影响了,因为所有的格子都已经访问过了,此时等循环结束后返回res即可,参见代码如下:

class Solution {
    public:
        int trapRainWater(vector<vector<int>>& heightMap) {
            if(heightMap.size()==0) return 0;
            priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> que;
            int row = heightMap.size(), col = heightMap[0].size();
            vector<vector<int>> visited(row, vector<int>(col, 0));
            int ans = 0, Max = INT_MIN;
            for(int i = 0; i < row; i++) {
                for(int j = 0; j < col; j++) {
                    if(!(i==0 || i==row-1 || j==0 || j==col-1)) continue;
                    que.push(make_pair(heightMap[i][j], i*col+j));
                    visited[i][j] = 1;
                }
            }
            vector<vector<int>> dir {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
            while(!que.empty()) {
                auto val = que.top();
                que.pop();
                int height = val.first, x = val.second/col, y = val.second%col;
                Max = max(Max, height);
                for(auto d: dir) {
                    int x2 = x + d[0], y2 = y + d[1];
                    if(x2>=row || x2<0 || y2<0 || y2>=col || visited[x2][y2]) continue;
                    visited[x2][y2] = 1;
                    if(heightMap[x2][y2] < Max) ans += Max - heightMap[x2][y2];
                    que.push(make_pair(heightMap[x2][y2], x2*col+y2));
                }
            }
            return ans;
        }
};
参考链接:http://www.cnblogs.com/grandyang/p/5928987.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值