Leetcode803. 打砖块—两种解法
方法一、深度优搜索(超时)
class Solution {
public int[] hitBricks(int[][] grid, int[][] hits) {
int len=hits.length;
int[] ret=new int[len];
int m=grid.length;
int n=grid[0].length;
for(int i=0;i<len;i++) {
int x=hits[i][0];
int y=hits[i][1];
if(grid[x][y]==0) ret[i]=0;
else {
grid[x][y]=0;
for(int j=0;j<4;j++) {
int[][] visited=new int[m][n];
index=0;
boolean flag=dfs(grid,visited,x+row[j],y+col[j],m,n,false);
if(!flag) {
visited=new int[m][n];
ret[i]+=index;
dfs(grid,visited,x+row[j],y+col[j],m,n,true);
}
}
}
}
return ret;
}
boolean dfs(int[][] grid,int[][] visited,int x,int y,int m,int n,boolean isClear) {
if(x<0 || x>=m || y<0 || y>=n || visited[x][y]==1 || grid[x][y]==0){
return false;
}
if(x==0) return true;
visited[x][y]=1;
if(isClear) grid[x][y]=0;
index++;
boolean flag=false;
for(int i=0;i<4;i++) {
int X=x+row[i];
int Y=y+col[i];
if(dfs(grid,visited,X,Y,m,n,isClear)) {
flag=true;
break;
}
}
return flag;
}
int index;
int[] row=new int[] {1,0,-1,0};
int[] col=new int[] {0,1,0,-1};
}
方法二、并查集+逆向思维
说明:简而言之就是在判断从后向前去补图 然后计算补充后的图中以房顶为根节点的一个连通图中结点增长的个数减去补充的那个点即为敲下这个结点后减少的结点。
class Solution {
private int rows;
private int cols;
private int[]X=new int[] {1,0,-1,0};
private int[]Y=new int[] {0,1,0,-1};
public int[] hitBricks(int[][] grid, int[][] hits) {
this.rows=grid.length;
this.cols=grid[0].length;
int[][] copy=new int[rows][cols];
for(int i=0;i<rows;i++) {
for(int j=0;j<cols;j++) {
copy[i][j]=grid[i][j];
}
}
int n=hits.length;
for(int i=0;i<n;i++) {
copy[hits[i][0]][hits[i][1]]=0;
}
int size=this.rows*this.cols;
unionFind unionfind=new unionFind(size+1);
for(int i=0;i<cols;i++) {
if(copy[0][i]==1)unionfind.union(i, size);
}
for(int i=1;i<rows;i++) {
for(int j=0;j<cols;j++) {
if(copy[i][j]==1) {
if(copy[i-1][j]==1) unionfind.union(getIndex(i, j), getIndex(i-1, j));
if(j-1>=0 && copy[i][j-1]==1) {
unionfind.union(getIndex(i, j), getIndex(i, j-1));
}
}
}
}
int[] ret=new int[n];
for(int i=n-1;i>=0;i--) {
int x=hits[i][0];
int y=hits[i][1];
if(grid[x][y]==0) {
ret[i]=0;
continue;
}
else {
int org=unionfind.getCount(size);
if(x==0) unionfind.union(y,size);
for(int j=0;j<4;j++) {
int preX=x+X[j]; int preY=y+Y[j];
if(preX>=0 && preX<rows && preY>=0 && preY<cols && copy[preX][preY]==1) {
unionfind.union(getIndex(preX, preY), getIndex(x, y));
}
}
int cur=unionfind.getCount(size);
ret[i]=Math.max(0, cur-org-1);
copy[x][y]=1;
}
}
return ret;
}
public int getIndex(int x,int y) {
return x*cols+y;
}
private class unionFind{
int[] parent;
int[] size;
unionFind(int n){
parent=new int[n];
size=new int[n];
for(int i=0;i<n;i++) {
parent[i]=i;
size[i]=1;
}
}
int find(int x) {
if(parent[x]!=x) {
parent[x]=find(parent[x]);
}
return parent[x];
}
public void union(int x,int y) {
int rootX=find(x);
int rootY=find(y);
if(rootX==rootY) return ;
parent[rootX]=rootY;
size[rootY]+=size[rootX];
}
public int getCount(int x) {
int root=find(x);
return size[root];
}
}
}