leetcode130. 被围绕的区域
给你一个m x n的矩阵board,由若干字符'X'和'O',找到所有被'X'围绕的区域,并将这些区域所有的'O'用'X'填充。
首先是想了很久的🤡错误解法:
class Solution {
public:
void dfs(vector<vector<char>>& board,int i,int j,bool &isEdge){
if(i == -1 || i == board.size() || j == -1 || j == board[0].size()) return;
if(board[i][j] == 'X' || board[i][j] == '-' || board[i][j] == 'E') return;
if(board[i][j] == 'O' && (i == 0 || i == board.size()-1 || j == 0 || j == board[0].size()-1)) isEdge = true;
board[i][j] = '-';//遍历过的网格点改为'-'
dfs(board,i-1,j,isEdge);dfs(board,i+1,j,isEdge);
dfs(board,i,j-1,isEdge);dfs(board,i,j+1,isEdge);
if(isEdge == true) board[i][j] = 'E';
}
void solve(vector<vector<char>>& board) {
for(int i = 0;i < board.size();++i){
for(int j = 0;j < board[0].size();++j){
bool isEdge = false;
dfs(board,i,j,isEdge);
}
}
for(int i = 0;i < board.size();++i){
for(int j = 0;j < board[0].size();++j){
if(board[i][j] == 'E') board[i][j] = 'O';
else board[i][j] = 'X';
}
}
}
};
错误分析
-
错误的全盘遍历逻辑
-
原代码遍历了整个矩阵的每一个单元格,对每个单元格都进行DFS判断
-
这会导致极端低效的 O(n^4) 时间复杂度(例如当整个矩阵都是O时)
-
正确做法应该只从边界出发进行DFS/BFS
-
-
错误的状态管理
-
使用成员变量
isEdge
会导致递归调用间的状态污染 -
当多个递归调用共享同一个状态变量时,会出现错误标记
-
正确解法
class Solution {
public:
// 深度优先搜索函数,用于标记与边界相连的'O'
void dfs(vector<vector<char>>& board, int i, int j) {
// 检查是否越界
if(i == -1 || i == board.size() || j == -1 || j == board[0].size())
return;
// 如果当前字符不是'O',直接返回
if(board[i][j] != 'O')
return;
// 将边界相连的'O'标记为'E'(Escape的缩写,表示可以逃出)
board[i][j] = 'E';
// 向四个方向继续深度搜索
dfs(board, i-1, j); // 上
dfs(board, i+1, j); // 下
dfs(board, i, j-1); // 左
dfs(board, i, j+1); // 右
}
void solve(vector<vector<char>>& board) {
// 获取矩阵的行数和列数
int m = board.size(), n = board[0].size();
// 第一步:标记所有与边界相连的'O'
// 遍历左右两条边
for(int i = 0; i < m; ++i) {
if(board[i][0] == 'O') // 左边界
dfs(board, i, 0);
if(board[i][n-1] == 'O') // 右边界
dfs(board, i, n-1);
}
// 遍历上下两条边(注意跳过角落,因为已经在上面处理过)
for(int j = 1; j < n - 1; ++j) {
if(board[0][j] == 'O') // 上边界
dfs(board, 0, j);
if(board[m-1][j] == 'O') // 下边界
dfs(board, m-1, j);
}
// 第二步:遍历整个矩阵,进行最终处理
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
if(board[i][j] == 'E')
// 被标记为'E'的恢复为'O'(这些是与边界相连的)
board[i][j] = 'O';
else
// 其他情况(包括原来的'O'和'X')
// 原来的'O'现在应该被包围,改为'X'
// 原来的'X'保持不变
board[i][j] = 'X';
}
}
}
};