题目描述:
给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。
找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
示例:
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’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
分析1:
我们可以嵌套两个for循环遍历每一个是’O’的位置,用dfs深度遍历该位置上的左右上下,如果左右上下都为‘X’那么就是被包围,因为避免重复递归----例如(1,1)位置上是’0’,dfs(1,2)位置时也去遍历dfs(1,1),这样就造成了死循环,所以我们每次遍历的时候在本位置上做一个记号,避免重复递归
代码1:
bool sol(vector<vector<char>>& board,int i,int j)
{
if(i >= board.size() || j >= board[0].size() ||
i < 0 || j < 0)
return false;
if(board[i][j] == 'X') return true;
if(board[i][j] == '-') return true;
else
{
if(i== 0 || j==0 || i == (board.size()-1) || j == (board[0].size()-1) ) return false;
board[i][j] = '-'; //在当前位置做一个标记
if(sol(board,i+1,j) & sol(board,i,j+1) &sol(board,i-1,j) & sol(board,i,j-1))
{
board[i][j] = 'X';
}
else
{
board[i][j] = 'O';
return false;
}
}
return true;
}
void solve(vector<vector<char>>& board)
{
if(board.size() < 3 || board[0].size() < 3) return ;
for(int i = 1;i<board.size()-1;i++)
{
for(int j = 1;j<board[0].size()-1;j++)
{
sol(board,i,j);
}
}
}
问题:
在递归过程中,如果递归的层次大于1时,我们做的标记会导致程序错误判断,如下图我们在遍历(3,2)位置时递归到(3,3)位置然后又递归到(2,3)位置,就出了错
分析2:
题目中给出,任何边界上的‘O’都不会被填充成‘X’,所以我们可以换个方向思考问题,只要是与边界上的’O’有直接或者间接相连的’O’就一定不会被填充成’X’,所以我们可以从边界上的’O’入手,dfs看哪些’O’与之相连,给这些’O’做上一个标记,最后遍历整个矩阵,没有标记的’O’改成’X’即可
代码2:
int n, m;///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();
遍历两列
for (int i = 0; i < n; i++) {
dfs(board, i, 0);
dfs(board, i, m - 1);
}
遍历两行
for (int i = 1; i < m - 1; i++) {
dfs(board, 0, i);
dfs(board, n - 1, i);
}
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';
}
}
}
}
注意事项:
拿到一个问题时,我们可以从多个方向来思考问题,不要局限于正向思考