leetcode 力扣 750 隔离病毒题解 算法题.docx
《leetcode 力扣 750 隔离病毒题解 算法题.docx》由会员分享,可在线阅读,更多相关《leetcode 力扣 750 隔离病毒题解 算法题.docx(21页珍藏版)》请在冰豆网上搜索。
leetcode力扣750隔离病毒题解算法题
题目:
隔离病毒
病毒扩散得很快,现在你的任务是尽可能地通过安装防火墙来隔离病毒。
假设世界由 mxn 的二维矩阵 isInfected 组成, isInfected[i][j]==0 表示该区域未感染病毒,而 isInfected[i][j]==1 表示该区域已感染病毒。
可以在任意2个相邻单元之间的共享边界上安装一个防火墙(并且只有一个防火墙)。
每天晚上,病毒会从被感染区域向相邻未感染区域扩散,除非被防火墙隔离。
现由于资源有限,每天你只能安装一系列防火墙来隔离其中一个被病毒感染的区域(一个区域或连续的一片区域),且该感染区域对未感染区域的威胁最大且保证唯一 。
你需要努力使得最后有部分区域不被病毒感染,如果可以成功,那么返回需要使用的防火墙个数;如果无法实现,则返回在世界被病毒全部感染时已安装的防火墙个数。
示例1:
输入:
isInfected=[[0,1,0,0,0,0,0,1],[0,1,0,0,0,0,0,1],[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0]]
输出:
10
解释:
一共有两块被病毒感染的区域。
在第一天,添加5墙隔离病毒区域的左侧。
病毒传播后的状态是:
第二天,在右侧添加5个墙来隔离病毒区域。
此时病毒已经被完全控制住了。
示例2:
输入:
isInfected=[[1,1,1],[1,0,1],[1,1,1]]
输出:
4
解释:
虽然只保存了一个小区域,但却有四面墙。
注意,防火墙只建立在两个不同区域的共享边界上。
示例 3:
输入:
isInfected=[[1,1,1,0,0,0,0,0,0],[1,0,1,0,1,1,1,1,1],[1,1,1,0,0,0,0,0,0]]
输出:
13
解释:
在隔离右边感染区域后,隔离左边病毒区域只需要2个防火墙。
提示:
•m== isInfected.length
•n== isInfected[i].length
•1<=m,n<=50
•isInfected[i][j] iseither 0 or 1
•在整个描述的过程中,总有一个相邻的病毒区域,它将在下一轮严格地感染更多未受污染的方块
语言:
Python
classSolution(object):
defcontainVirus(self,grid):
R,C=len(grid),len(grid[0])
defneighbors(r,c):
fornr,ncin((r-1,c),(r+1,c),(r,c-1),(r,c+1)):
if0<=nryieldnr,nc
defdfs(r,c):
if(r,c)notinseen:
seen.add((r,c))
regions[-1].add((r,c))
fornr,ncinneighbors(r,c):
ifgrid[nr][nc]==1:
dfs(nr,nc)
elifgrid[nr][nc]==0:
frontiers[-1].add((nr,nc))
perimeters[-1]+=1
ans=0
whileTrue:
#Findallregions,withassociatedfrontiersandperimeters.
seen=set()
regions=[]
frontiers=[]
perimeters=[]
forr,rowinenumerate(grid):
forc,valinenumerate(row):
ifval==1and(r,c)notinseen:
regions.append(set())
frontiers.append(set())
perimeters.append(0)
dfs(r,c)
#Iftherearenoregionsleft,break.
ifnotregions:
break
#Addtheperimeteroftheregionwhichwillinfectthemostsquares.
triage_index=frontiers.index(max(frontiers,key=len))
ans+=perimeters[triage_index]
#Triagethemostinfectiousregion,andspreadtherestoftheregions.
fori,reginenumerate(regions):
ifi==triage_index:
forr,cinreg:
grid[r][c]=-1
else:
forr,cinreg:
fornr,ncinneighbors(r,c):
ifgrid[nr][nc]==0:
grid[nr][nc]=1
returnans
语言:
Java
classSolution{
Setseen;
List>regions;
List>frontiers;
Listperimeters;
int[][]grid;
intR,C;
int[]dr=newint[]{-1,1,0,0};
int[]dc=newint[]{0,0,-1,1};
publicintcontainVirus(int[][]grid){
this.grid=grid;
R=grid.length;
C=grid[0].length;
intans=0;
while(true){
seen=newHashSet();
regions=newArrayList();
frontiers=newArrayList();
perimeters=newArrayList();
for(intr=0;rfor(intc=0;cif(grid[r][c]==1&&!
seen.contains(r*C+c)){
regions.add(newHashSet());
frontiers.add(newHashSet());
perimeters.add(0);
dfs(r,c);
}
}
}
if(regions.isEmpty())break;
inttriageIndex=0;
for(inti=0;iif(frontiers.get(triageIndex).size()triageIndex=i;
}
ans+=perimeters.get(triageIndex);
for(inti=0;iif(i==triageIndex){
for(intcode:
regions.get(i))
grid[code/C][code%C]=-1;
}else{
for(intcode:
regions.get(i)){
intr=code/C,c=code%C;
for(intk=0;k<4;++k){
intnr=r+dr[k],nc=c+dc[k];
if(nr>=0&&nr=0&&ncgrid[nr][nc]=1;
}
}
}
}
}
returnans;
}
publicvoiddfs(intr,intc){
if(!
seen.contains(r*C+c)){
seen.add(r*C+c);
intN=regions.size()
regions.get(N-1).add(r*C+c);
for(intk=0;k<4;++k){
intnr=r+dr[k],nc=c+dc[k];
if(nr>=0&&nr=0&&ncif(grid[nr][nc]==1){
dfs(nr,nc);
}elseif(grid[nr][nc]==0){
frontiers.get(N-1).add(nr*C+nc);
perimeters.set(N-1,perimeters.get(N-1)+1);
}
}
}
}
}
}
语言:
cpp
constintN=55;
classSolution{
public:
intres;
constintdir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//方向变量
intn,m;//row,col
boolvi[55][55];//访问标记
intCal(vector>&g,intx,inty){
//计算有(x,y)的区域的危险度
queueq;
unordered_setst;//会感染的位置集合自动去重
vi[x][y]=true;
q.push(x*N+y);
while(!
q.empty()){
intt=q.front();q.pop();
intu=t/N;
intv=t%N;
for(inti=0;i<4;i++){
intnx=u+dir[i][0];
intny=v+dir[i][1];
if(nx<0||nx==n||ny<0||ny==m||g[nx][ny]==2||vi[nx][ny])continue;//表示下一个是墙或者已经访问过了
if(g[nx][ny]==0){//如果是0说明这块是要感染的
st.insert(nx*N+ny);
}elseif(g[nx][ny]){//否则加入队列
vi[nx][ny]=true;
q.push(nx*N+ny);
}
}
}
returnst.size();
}
voidhelp_close(vector>&g,intx,inty){
//安装挡板操作变成2表示变成墙了
queueq;
vi[x][y]=true;
g[x][y]=2;
q.push(x*N+y);
while(!
q.empty()){
intt=q.front();q.pop();
intu=t/N;
intv=t%N;
for(inti=0;i<4;i++){
intnx=u+dir[i][0];
intny=v+dir[i][1];
if(nx<0||nx==n||ny<0||ny==m||vi[nx][ny]||g[nx][ny]==2)continue;//表示下一个是墙或者已经访问了
if(g[nx][ny]==0){
res++;//需要安装挡板
continue;
}
vi[nx][ny]=true;
g[nx][ny]=2;
q.push(nx*N+ny);
}
}
}
voidhelp_spread(vector>&g,intx,inty){
//含有(x,y)点的连通区域开始扩散
queueq;
vi[x][y]=true;
q.push(x*N+y);
while(!
q.empty()){
intt=q.front();q.pop();
intu=t/N;
intv=t%N;
for(inti=0;i<4;i++){
intnx=u+dir[i][0];
intny=v+dir[i][1];
if(nx<0||nx==n||ny<0||ny==m||vi[nx][ny]||g[nx][ny]==2)continue;//访问过了
if(g[nx][ny]==0){
g[nx][ny]=1;
vi[nx][ny]=true;
continue;
}
vi[nx][ny]=true;
q.push(nx*N+ny);
}
}
}
intcontainVirus(vector>&g){
//按照题目意思模拟即可
//重点就是如何判断每一个连通区域
res=0;
n=g.size(),m=g[0].size();
while(true){
//直到没有空闲位置或者全部被封闭
for(inti=0;iintx,y,curn;
curn=-1;//当前的威胁
intnum=0;//连通区域的个数
vectorh;//存储每一个联通块中的一个点
for(inti=0;ifor(intj=0;jif(!
vi[i][j]&&g[i][j]==1){
num++;
h.push_back(i*N+j);
intt=Cal(g,i,j);
if(t>curn)x=i,y=j,curn=t;
}
}
}
if(num==0)returnres;//如果没有一个病毒块则直接返回
for(inti=0;ihelp_close(g,x,y);//把威胁最大的连通块放置挡板
if(num==1)break;
//剩下的进行扩散
for(auto&i:
h){
intu=i/N;
intv=i%N;
if(vi[u][v])continue;
help_spread(g,u,v);//扩散
}
}
returnres;
}
};
语言:
cpp
/*
*/
classSolution{
private:
structArea
{
unordered_setdead;
unordered_settoDead;
//设置障碍的数量
intcnt=0;
};
//数组的行数和列数
introws;
intcols;
bool**visited;
//遍历四个方向,写到一个数组里了
intdires[5]={0,1,0,-1,0};
//基于深度优先的找没处理病毒区域(grid[x][y]==1)
voiddfs(constvector>&grid,Area&area,intx,inty)
{
if(grid[x][y]==0)
{
++t;
area.toDead.insert(x*50+y);
}
else
{
//其实这里只有1的情况,-1已经隔离的病毒在下面会过滤
area.dead.insert(x*50+y);
visited[x][y]=true;
//四个方向去查找1
for(intk=0;k<4;++k)
{
intnx=x+dires[k];
intny=y+dires[k+1];
//有效范围;没有遍历;且没被隔离
if(nx>=0&&nx=0&&nyvisited[nx][ny]&&grid[nx][ny]!
=-1)
{
dfs(grid,area,nx,ny);
}
}
}
}
public:
intcontainVirus(vector>&grid){
rows=grid.size();
cols=grid[0].size();
intres=0;
//visisted来避免循环遍历
visited=newbool*[rows];
for(inti=0;i{
visited[i]=newbool[cols];
memset(visited[i],0,sizeof(bool)*cols);
}
while(true)
{
for(inti=0;i{
memset(visited[i],0,sizeof(bool)*cols);
}
//用一个简单数组记录最大值来模拟优先队列
vectorq;
intmaxIndex=0;
//遍历每个点去dfs找区域
for(inti=0;i{
for(intj=0;j{
//只有没遍历,而且为没隔离的病毒区域才考虑
if(!
visited[i][j]&&grid[i][j]==1)
{
Areaarea;
dfs(grid,area,i,j);
q.emplace_back(area);
if(area.toDead.size()>q[maxIndex].toDead.size())
{
maxIndex=q.size()-1;
}
}
}
}
//所有病毒都处理完
if(q.empty())
{
break;
}
intn=q.size();
for(inti=0;i{
auto&a=q[i];
if(i!
=maxIndex)
{
for(constint&p:
a.toDead)
{
grid[p/50][p%50]=1;
}
}
else
{
for(constint&p:
a.dead)
{
grid[p/50][p%50]=-1;
}
res+=t;
}
}
}
returnres;
}
};
语言:
cpp
classSolution{
public:
intflag;
intm;
intn;
intex[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
boolisvalidxy(intx,inty)
{
return(x>=0&&x=0&&y}
voiddfsarea(vector>&grid,vector&st,vector>&vst,set&toinject,vector&inject,int&sfn)
{
intlen=st.size();
if(len==0)
{
return;
}
vectornewst;
for(inti=0;i{
intx=st[i]/n;
inty=st[i]%n;
for(intj=0;j<4;j++)
{
intnx=x+ex[j][0];
intny=y+ex[j][1];
if(!
isvalidxy(nx,ny)||vst[nx][ny]==1)
{
continue;
}
if(grid[nx][ny]==0)
{
toinject.insert(nx*n+ny);
sfn++;
continue;
}
elseif(grid[nx][ny]==1)
{
newst.push_back(nx*n+ny);
vst[nx][ny]=1;
inject.push_back(nx*n+ny);
}
}
}
dfsarea(grid,newst,vst,toinject,inject,sfn);
}
voidsetarea(vector>&grid,vector&st,intflag)
{
intlen=st.size();
for(inti=0;i{
intx=st[i]/n;
inty=st[i]%n;
grid[x][y]=flag;
}
}
voidsetarea(vector>&grid,set&st,intflag)
{
for(autoit=st.begin()