被围绕的区域
题意为使不与边界上的‘O’相连的‘O’的连通分支都变为‘X’。
我们可以利用dfs从边界上开始搜索,将含有边界上‘O’的所有‘O’的连通分支全部感染成另一个字符,不含边界的‘O’的连通分支不变。
最后遍历整个数组,将所有‘O’全变为‘X’,因为此时和边界相连的‘O’已经悉数变为了另一个字符,再将所有的另一个字符变为‘O’即可。
DFS
class Solution {
public:
int m,n;
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};
bool restrain(int x,int y)
{
return (x>=0&&x<m&&y>=0&&y<n);
}
void dfs(vector<vector<char>>& board,int x,int y)
{
if(!restrain(x,y)||board[x][y]=='*'||board[x][y]=='X') return ;
board[x][y]='*';
for(int i=0;i<4;i++)
{
dfs(board,x+dx[i],y+dy[i]);
}
}
void solve(vector<vector<char>>& board) {
m=board.size();
n=board[0].size();
if(m<=2||n<=2) return ;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if((i==0||j==0||i==m-1||j==n-1)&&board[i][j]=='O')
{
dfs(board,i,j);
}
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(board[i][j]=='O')
board[i][j]='X';
if(board[i][j]=='*')
board[i][j]='O';
}
}
}
};
BFS和DFS的思路相同,只是遍历的方式不一样。
BFS
class Solution {
public:
int m,n;
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};
bool restrain(int x,int y)
{
return (x>=0&&x<m&&y>=0&&y<n);
}
void bfs(vector<vector<char>>& board,int x,int y)
{
queue<pair<int ,int>> a;
board[x][y]='*';
a.emplace(x,y);
while(!a.empty())
{
x=a.front().first,y=a.front().second;
a.pop();
for(int i=0;i<4;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(restrain(tx,ty)&&board[tx][ty]!='*'&&board[tx][ty]!='X')
{
board[tx][ty]='*';
a.emplace(tx,ty);
}
}
}
}
void solve(vector<vector<char>>& board) {
m=board.size();
n=board[0].size();
if(m<=2||n<=2) return ;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if((i==0||j==0||i==m-1||j==n-1)&&board[i][j]=='O')
{
bfs(board,i,j);
}
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(board[i][j]=='O')
board[i][j]='X';
if(board[i][j]=='*')
board[i][j]='O';
}
}
}
};
并查集
class Solution {
public:
vector<int >a;
vector<int >h;
void unionfind(int n)
{
for(int i=0;i<n;i++)
{
a.push_back(i);
h.push_back(0);
}
}
int find(int x)
{
return x==a[x]? x :a[x] = find(a[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
else
{
if(h[x]<h[y])
{
a[x]=y;
}
else
{
a[y]=x;
if(h[x]==h[y]) h[x]++;
}
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int m,n;
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};
bool restrain(int x,int y)
{
return (x>=0&&x<m&&y>=0&&y<n);
}
void solve(vector<vector<char>>& board) {
m=board.size();
n=board[0].size();
if(m<=2||n<=2) return ;
unionfind(m*n+1);
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if((i==0||j==0||i==m-1||j==n-1)&&board[i][j]=='O')
{
unite(n*m,i*n+j);
}
else if(board[i][j]=='O')
{
for(int k=0;k<4;k++)
{
int tx=i+dx[k];
int ty=j+dy[k];
if(restrain(tx,ty)&&board[tx][ty]=='O')
{
unite(i*n+j,tx*n+ty);
}
}
}
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(board[i][j]=='O'&&!same(i*n+j,m*n))
{
board[i][j]='X';
}
}
}
}
};
这是一道和连通分支打交道的题目,我们可以考虑利用并查集解决。
我们附设一个特殊的节点m*n
,将所有和边界‘O’相连的连通分支和特殊的节点合并,最后遍历数组如果数组中的‘O’和特殊的节点的根不相同(不属于同一连通分支),则说明他们是不与边界上的‘O’相连的‘O’的连通分支
,将他们变为‘X’。