LeetCode每日一题-407.接水滴-2021-11-4
作者:互联网
LeetCode每日一题--407.接雨水②(困难)
2021.11.4,真是给我难的不轻
题目链接:https://leetcode-cn.com/problems/trapping-rain-water-ii/
1.题目描述
大早上起来看见困难题目,内心都已经凉了半截,哈哈
2.题目探讨
在我一开始看见这个题目的时候,我第一反应是使用单调栈,单调栈算法是维护一个递增,或者递减的栈,持续读入数据,找到任意一个元素周围比它大或者比它小的时间复杂度为O(N)的算法。具体可以看看这个博客:https://zhuanlan.zhihu.com/p/101785785,所以这里我一开始的想法:
初始做法:
- 在每一行保持一个单调递减的栈,然后当找到下一个元素比当前的栈顶的元素大的时候,弹出栈顶元素,求出该元素和两边元素的差值的 最小值,然后在该元素所在列再次求一个单调栈,xxxx
缺点:
- 缺点也很明显,时间复杂度太高,并且我在纸上模拟的过程中发现,可能有的块是无法正常求出来的
tips:偷偷摸摸的看了题解
这道题要明确的两个要点:
- 所给二维矩阵最外侧的元素是无法储存水的
- 储水的块,它的四周(可以延伸到最外侧,并不一定是说它的上下左右四周)的块高度比它高
那么我们实际上选择的做法是广度优先算法,从最外层开始包围这个矩阵,并且当一个块储存了水之后,它的高度就会发生变化,这个时候它就可以影响它周围的块
图示(以给出的例一为例):
在对外层使用优先队列排序之后是这个样子,我们保持队列是升序排列,这样我们每次总队列头部取出的元素就可以保证是当前最外层高度最小的元素,我们对于取出来的元素进行下列操作:
- 查看四周是否有比自己高度小的,若存在-->则注水(因为目前弹出来的元素是包围圈里面高度最小的,这个还小,我们就可以注水了),若不存在-->将比自己高的加入队列中,作为包围圈
- 弹出这个元素,并且标识这个元素已经遍历过了
代码演示:
import java.util.PriorityQueue;
class Solution {
/*
* 明确两个前提:
* - 四周的方块不能储存水
* - 方块储存水的时候,要比它周围的方块都低
*
* 1.取四周的点加入队列
* */
public int trapRainWater(int[][] heightMap)
{
if(heightMap.length<=2||heightMap[0].length<=2)
return 0;
//row,col;
int row=heightMap.length,col=heightMap[0].length;
//创建visit数组
boolean [][]visit=new boolean[row][col];
//创建小顶堆,降序排列
PriorityQueue<int[]> pq=new PriorityQueue<>((o1,o2)->o1[1]-o2[1]);
//添加四周的元素,并且visit更改
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
{
if(i==0||j==0||i==row-1||j==col-1)
{
pq.offer(new int [] {i*col+j,heightMap[i][j]});
visit[i][j]=true;
}
}
int []dir= {-1,0,1,0,-1};
int res=0;
while(!pq.isEmpty())
{
int []cur=pq.poll();
int inx=cur[0]/col;
int iny=cur[0]%col;
for(int i=0;i<4;i++)
{
int opx=inx+dir[i];
int opy=iny+dir[i+1];
if(opx>0&&opx<row&&opy>0&&opy<col&&!visit[opx][opy])
{
if(heightMap[opx][opy]<cur[1])
{
res+=cur[1]-heightMap[opx][opy];
pq.offer(new int[]{opx*col+opy,cur[1]});
}
else {
pq.offer(new int[]{opx*col+opy,heightMap[opx][opy]});
}
visit[opx][opy]=true;
}
}
}
return res;
}
}
实话实说确实难,看了题解也看了好大一会,比我将的好的题解附带上链接:
标签:11,题目,队列,题解,元素,407,--,2021,四周 来源: https://www.cnblogs.com/oldoldcoder/p/15508998.html