题目
中等
相关标签
相关企业
给你一个 m x n
的矩阵 board
,由若干字符 'X'
和 'O'
,找到所有被 'X'
围绕的区域,并将这些区域里所有的 'O'
用 'X'
填充。
示例 1:
输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]] 输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]] 解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的'O'
都不会被填充为'X'
。 任何不在边界上,或不与边界上的'O'
相连的'O'
最终都会被填充为'X'
。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
示例 2:
输入:board = [["X"]] 输出:[["X"]]
提示:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j]
为'X'
或'O'
通过次数 285.7K
提交次数 614.4K
通过率 46.5%
方法一:并查集
利用并查集,将相邻的相同字母视为一个连通集。边界上的'O'视为同一个集,易得,不与边界上的'O'相邻的'O'即为被围绕的区域。
下面是某位大佬的java代码
class UnionFind {
int[] parents;
public UnionFind(int totalNodes) {
parents = new int[totalNodes];
for (int i = 0; i < totalNodes; i++) {
parents[i] = i;
}
}
// 合并连通区域是通过find来操作的, 即看这两个节点是不是在一个连通区域内.
void union(int node1, int node2) {
int root1 = find(node1);
int root2 = find(node2);
if (root1 != root2) {
parents[root2] = root1;
}
}
int find(int node) {
while (parents[node] != node) {
// 当前节点的父节点 指向父节点的父节点.
// 保证一个连通区域最终的parents只有一个.
parents[node] = parents[parents[node]];
node = parents[node];
}
return node;
}
boolean isConnected(int node1, int node2) {
return find(node1) == find(node2);
}
}
class Solution {
int rows;
int cols;
public void solve(char[][] board) {
if (board == null || board.length == 0)
return;
rows = board.length;
cols = board[0].length;
// 用一个虚拟节点, 边界上的O 的父节点都是这个虚拟节点
UnionFind uf = new UnionFind(rows * cols + 1);
int dummyNode = rows * cols;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (board[i][j] == 'O') {
// 遇到O进行并查集操作合并
if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {
// 边界上的O,把它和dummyNode 合并成一个连通区域.
uf.union(node(i, j), dummyNode);
} else {
// 和上下左右合并成一个连通区域.
if (i > 0 && board[i - 1][j] == 'O')
uf.union(node(i, j), node(i - 1, j));
if (i < rows - 1 && board[i + 1][j] == 'O')
uf.union(node(i, j), node(i + 1, j));
if (j > 0 && board[i][j - 1] == 'O')
uf.union(node(i, j), node(i, j - 1));
if (j < cols - 1 && board[i][j + 1] == 'O')
uf.union(node(i, j), node(i, j + 1));
}
}
}
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (uf.isConnected(node(i, j), dummyNode)) {
// 和dummyNode 在一个连通区域的,那么就是O;
board[i][j] = 'O';
} else {
board[i][j] = 'X';
}
}
}
}
int node(int i, int j) {
return i * cols + j;
}
}
方法二:深度优先搜索
前面提到,不与边界的'O'连通的'O'即为被包围的区域。所以我们可以以四条边上的'O'为起点搜索,将与边界'O'连通的'O'做个标记,随后有标记的'O'就改回'O',没有标记的'O'就变成'X'。
class Solution {
public:
void dfs(vector<vector<char>>& board,int x,int y,int n,int m)
{
if(x<0||x>=n||y<0||y>=m||board[x][y]!='O')
{
return;
}
board[x][y]='Y';
dfs(board,x+1,y,n,m);
dfs(board,x,y-1,n,m);
dfs(board,x-1,y,n,m);
dfs(board,x,y+1,n,m);
}
void solve(vector<vector<char>>& board) {
int n=board.size();
if(n==1) return;
int m=board[0].size();
if(m==1) return;
for(int i=0;i<n;i++)
{
dfs(board,i,0,n,m);
dfs(board,i,m-1,n,m);
}
for(int j=1;j<m-1;j++)
{
dfs(board,0,j,n,m);
dfs(board,n-1,j,n,m);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(board[i][j]=='Y')
board[i][j]='O';
else if(board[i][j]=='O')
board[i][j]='X';
}
}
}
};