LeetCode | 407. Trapping Rain Water II矩阵存水难题算法

Givenan m x n matrix of positive integers representing the height of eachunit cell in a 2D elevation map, compute the volume of water it is able to trapafter raining.

Note:
Both
 m and n are less than 110. The height of each unit cell is greaterthan 0 and is less than 20,000.

Example:

Given the following 3x6 height map:

[

  [1,4,3,1,3,2],

  [3,2,1,3,2,4],

  [2,3,3,2,3,1]

]

 

Return 4.


The above image represents the elevation map
 [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] before the rain.


After the rain, water is trapped between the blocks. The total volume of watertrapped is 4.

题目的大概思路是,维护一个优先级队列mark,这个队列中的cell,按照其height按照从小到大的顺序排列。

Mark中的所有cell必定围成一个环,这个环和最开始给定的矩阵的外边界之间的所有节点都认为已经访问过了,并且所有可能存水的节点的存水的值都得到了累计,并且mark中最小的height表示,Mark中的所有cell围成的一个环,所有包含这个环的环中最小height最大的一个环的height,

Mark初始化为最开始给定的矩阵的外边界,这个时候mark环和最开始给定的矩阵的外边界之间的所有节点都认为已经访问过了,并且以上范围内所有可能存水的节点的存水的值都得到了累计,每次选取mark中height最小的一个节点u,遍历所有u节点的相邻节点,如果这个节点存在且没有访问过,比较这个节点和u节点的height,如果这个节点height比u节点height大, 直接把这个节点加入mark,如果这个节点height没有u节点的height大,则这个节点必定能够累积其height之差的水,并且将这个节点height设置的u节点的height,将这个节点加入mark。

当进行以上一个过程之后,可以证明,这个时候mark环和最开始给定的矩阵的外边界之间的所有节点都已经访问过了,并且存水量都已经确定了,这个时候mark中最小的height表示,Mark中的所有cell围成的一个环,所有包含这个环的环中最小height最大的一个环的height。

持续以上过程直到矩阵中所有节点的存水量都已经得到了确认,这个时候的总存水量就是最终的结果。

这题还要记住,有关优先集队列管理其元素排序方法的两种方法,第一种方法是使用操作符重载,比如这一题,使用  friend bool operator <(const cell & a,const cell & b)

这里一定要注意,一定要有friend友元标记,一定要写在数据结构的里面,虽然并不知道这是为什么,

方法二是使用比较对象,比如这样struct cmp1{    

    bool operator ()(int &a,int &b){    

        return a>b;//最小值优先    

    }    

};  

这里需要记住,符号按照<来处理

class Solution {
public:
   struct cell {
	int x; int y;
	int height;
	cell(int x2=0, int y2=0, int height2=0) : x(x2), y(y2), height(height2) {}
    friend bool operator < (const cell & a,const cell & b)
  {
	return a.height > b.height;
  }
};

int trapRainWater(vector<vector<int>>& heightMap) {
	priority_queue<cell> mark;
	int r = heightMap.size();
    if (r == 0) return 0;
	int c = heightMap[0].size();
	vector<vector<bool>> vst(r, vector<bool>(c, false));
	for (int i = 1; i < c - 1; i++) {
		mark.push(cell(0,i,heightMap[0][i]));
		mark.push(cell(r-1, i, heightMap[r-1][i]));
		vst[0][i] = true; vst[r-1][i] = true;
	}
	for (int i = 1; i < r - 1; i++) {
		mark.push(cell(i, 0, heightMap[i][0]));
		mark.push(cell(i, c-1, heightMap[i][c-1]));
		vst[i][0] = true; vst[i][c-1] = true;
	}
	int rm[4] = { -1,0,1,0 };
	int cm[4] = { 0,1,0,-1 };

	int theAllWater = 0;
	while (!mark.empty())
	{
		cell u = mark.top(); mark.pop();
		int nr, nc;
		for (int i = 0; i < 4; i++)
		{
			nr = u.x + rm[i];
			nc = u.y + cm[i];
			if (nr > 0 && nr < r&&nc>0 && nc < c - 1 && (!vst[nr][nc]))
			{
				vst[nr][nc] = true;
				if (heightMap[nr][nc] < u.height)
				{
					theAllWater += (u.height - heightMap[nr][nc]);
					mark.push(cell(nr, nc, u.height));
				}
				else
				{
					mark.push(cell(nr, nc, heightMap[nr][nc]));
				}
			}
		}
	}
	return theAllWater;
}
};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值