给你一个 m x n
的矩阵 board
,由若干字符 'X'
和 'O'
组成,捕获 所有 被围绕的区域:
- 连接:一个单元格与水平或垂直方向上相邻的单元格连接。
- 区域:连接所有
'O'
的单元格来形成一个区域。 - 围绕:如果您可以用
'X'
单元格 连接这个区域,并且区域中没有任何单元格位于board
边缘,则该区域被'X'
单元格围绕。
通过将输入矩阵 board
中的所有 '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"]]
解释:
在上图中,底部的区域没有被捕获,因为它在 board 的边缘并且不能被围绕。
示例 2:
输入:board = [["X"]]
输出:[["X"]]
提示:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j]
为'X'
或'O'
解法一:深度优先遍历
class Solution {
public:
int n, m;
void dfs(vector<vector<char>>& board, int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m || board[x][y] != 'O') {
return;
}
board[x][y] = 'A'; // 标记为 'A'
// 递归调用四个方向
dfs(board, x + 1, y);
dfs(board, x - 1, y);
dfs(board, x, y + 1);
dfs(board, x, y - 1);
}
void solve(vector<vector<char>>& board) {
n = board.size();
if (n == 0)
return;
m = board[0].size();
// 从第一列和最后一列进行 DFS
for (int i = 0; i < n; i++) {
dfs(board, i, 0); // 左边界
dfs(board, i, m - 1); // 右边界
}
// 从第一行和最后一行进行 DFS
for (int i = 1; i < m - 1; i++) {
dfs(board, 0, i); // 上边界
dfs(board, n - 1, i); // 下边界
}
// 更新 board,将 'A' 还原为 'O',将 'O' 变为 'X'
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] == 'A')
board[i][j] = 'O';
else if (board[i][j] == 'O')
board[i][j] = 'X';
}
}
}
};
解决思路如下:
- 首先定义了变量n和m,分别存储矩阵的行数和列数。
- 定义了dfs函数,用于进行深度优先搜索。dfs函数的输入参数有目标矩阵board,当前搜索位置的坐标x和y。
- 在dfs函数中,首先进行边界条件判断。如果当前坐标超出了矩阵的范围,或者当前位置上的字符不是'O',则直接返回。
- 如果当前位置上的字符是'O',则将其改为字符'A',表示已经访问过。
- 递归调用dfs函数,分别搜索四个方向上的相邻位置:右、左、下、上。
- 在solve函数中,首先获取矩阵的行数和列数,并进行边界判断,如果行数为0,则直接返回。
- 接着从第一列和最后一列开始进行dfs搜索,对于每一行,分别调用dfs函数,传入矩阵坐标i和列坐标0以及列坐标m-1。
- 再从第一行和最后一行开始进行dfs搜索,对于每一列,分别调用dfs函数,传入矩阵坐标0和行坐标i以及行坐标n-1。
- 最后,遍历整个矩阵,将字符'A'改为'O',将字符'O'改为'X'。
整体思路是从矩阵的边界开始进行DFS搜索,将所有与边界相连的字符'O'标记为字符'A',表示不会被改变的区域。然后再遍历整个矩阵,将字符'O'改为字符'X',将字符'A'改回字符'O',即实现了将被围绕的区域替换为'X'的要求。
解法二:广度优先遍历
class Solution {
public:
const int dx[4] = {1, -1, 0, 0};
const int dy[4] = {0, 0, 1, -1};
void solve(vector<vector<char>>& board) {
int n=board.size();
if(n==0)
return ;
int m=board[0].size();
queue<pair<int ,int>> que;
for(int i=0;i<n;i++){
if(board[i][0]=='O'){
que.emplace(i,0);
board[i][0]='A';
}
if(board[i][m-1]=='O'){
que.emplace(i,m-1);
board[i][m-1]='A';
}
}
for(int i=1;i<m-1;i++){
if(board[0][i]=='O'){
que.emplace(0,i);
board[0][i]='A';
}
if(board[n-1][i]=='O'){
que.emplace(n-1,i);
board[n-1][i]='A';
}
}
while(!que.empty()){
int x=que.front().first,y=que.front().second;
que.pop();
for(int i=0;i<4;i++){
int mx=x+dx[i],my=y+dy[i];
if(mx<0||my<0||mx>=n||my>=m||board[mx][my]!='O')
continue;
que.emplace(mx,my);
board[mx][my]='A';
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(board[i][j]=='A')
board[i][j]='O';
else if(board[i][j]=='O')
board[i][j]='X';
}
}
}
};
解决思路如下:
- 首先定义了常量数组dx和dy,表示四个方向的x和y的增量。
- 定义了solve函数,用于解决问题。solve函数的输入参数是二维字符矩阵board。
- 首先获取矩阵的行数n和列数m,并进行边界判断,如果行数为0,则直接返回。
- 定义一个队列que,用于存储待访问的坐标。
- 遍历矩阵的边界,如果当前位置上的字符是'O',则将其坐标加入队列que,并将其标记为字符'A'。
- 使用队列进行广度优先搜索。当队列不为空时,取出队首元素,获取其坐标x和y。
- 遍历四个方向,计算出相邻位置的坐标mx和my。
- 如果相邻位置超出了矩阵的范围,或者相邻位置上的字符不是'O',则跳过当前方向。
- 如果相邻位置上的字符是'O',则将其坐标加入队列que,并将其标记为字符'A'。
- 当队列为空时,表示所有与边界相连的字符'O'都已经标记为字符'A'。
- 遍历整个矩阵,将字符'A'改为字符'O',将字符'O'改为'X'。
整体思路是从矩阵的边界开始进行广度优先搜索,将所有与边界相连的字符'O'标记为字符'A',表示不会被改变的区域。然后再遍历整个矩阵,将字符'O'改为字符'X',将字符'A'改回字符'O',即实现了将被围绕的区域替换为'X'的要求。