思路1:DFS
- 第一步,先把所有边界,以及和边界相关的格子,统统标记为A
 - 第二步,把所有内部的O统统变成X,但是所有的A统统变成O
 - 所以,问题的关键在于,如果找出所有边界上的字符。
 - 
思路2:BFS
 大的思路延续DFS的办法
- 改变之处在于,如果通过BFS的策略,找到所有边缘上的’O’和它的兄弟姐妹
 - 将当前扫描到的位置
{x,y}记为root根节点 - 上下左右的四个位置,符合条件的位置,记为下一层的节点,然后以此类推。
 注意,一旦进入队列之后,需要立即改变标记为’A’,否则会出现多次重复进入队列的问题。
代码2:
class Solution {public:int move_pos[4] = {1, 0, -1, 0};void bfs(vector<vector<char>>& board, int x, int y, int row, int col) {board[x][y] = 'A';queue<pair<int,int>> q;q.push({x, y});while (!q.empty()) {int cur_level_size = q.size();for (int i = 0; i < cur_level_size; ++i) {pair<int,int> cur_pos = q.front();int cur_x = q.front().first, cur_y = q.front().second;q.pop();for (int i = 0; i < 4; ++i) {int next_x = cur_x + move_pos[i];int next_y = cur_y + move_pos[(i + 1) % 4];if (next_x < 0 || next_x >= row || next_y < 0 || next_y >= col || board[next_x][next_y] != 'O' ) {continue;} else {}}}}}void solve(vector<vector<char>>& board) {int row = board.size();int col = board[0].size();// 第1步,将所有边上的O,和它的兄弟姐妹,统统标记成Afor (int i = 0; i < row; ++i) {if(board[i][0] == 'O')bfs(board, i, 0, row, col);if(board[i][col - 1] == 'O')bfs(board, i, col - 1, row, col);}for (int i = 0; i < col; ++i) {if (board[0][i] == 'O')bfs(board, 0, i, row, col);if (board[row - 1][i] == 'O')bfs(board, row - 1, i, row, col);}// 第2步,将所有O变成Xfor (int i = 0; i < row; ++i) {for (int j = 0; j < col; ++j) {if (board[i][j] == 'A') {board[i][j] = 'O';} else if (board[i][j] == 'O') {board[i][j] = 'X';}}}}};
两个细节:
如何改变方向:
int move_pos[4] = {1, 0, -1, 0}; int next_x = cur_x + move_pos[i]; int next_y = cur_y + move_pos[(i + 1) % 4];如何避免重复进入队列(一进入队列立即标记)
q.push({next_x, next_y}); // 进入队列之后,立即改变标号,这样可以避免重复进入队列的问题 board[next_x][next_y] = 'A';思路3:并查集
- 并查集,3个步骤
 - 对于所有位于边界上的点,和“特殊点”放到一组
 - 对于所有内部的点,和上下左右可以连通的点放到一起
 - 如果内部和边界联系上了,也就是和“特殊点”在一起,那么,就变成‘O’,如果和边界上的点联系不到一起,那么就是’X’
 - 小trick:利用
node(i, j) = i * col + j将二维的点映射成一维的数字代码3:并查集
```cpp class Solution { private: int row, col; unordered_mapfa, r; int dx[4] = {1, 0, -1, 0}; int dy[4] = {0, 1, 0, -1};  
public: void init(int n) { for (int i = 0; i <= n; i++) { fa[i] = i; r[i] = 1; } }
int find(int x) {
    if (fa[x] != x) {
        fa[x] = find(fa[x]);
    }
    return fa[x];
}
void merge(int i, int j) {
    int x = find(i), y = find(j);
    if (x != y) {
        if (r[x] <= r[y]) {
            fa[x] = y;
        } else {
            fa[y] = x;
        }
        if (r[x] == r[y]) {
            r[y] += 1;
        }
    }
}
// 2维坐标到1维数字
int node(int i, int j) {
    return i * col + j;
}
bool check(int i, int j) {
    if (0 <= i && i <= row - 1 && 0 <= j && j <= col - 1) {
        return true;
    }
    return false;
}
void solve(vector<vector<char>>& board) {
    // 并查集,3个步骤
    // 1. 对于所有位于边界上的点,和特殊点放到一起
    // 2. 对于所有内部的点,和上下左右可以连通的点放到一起
    // 3. 如果内部和边界联系上了,也就是和“特殊点”在一起,那么,就变成‘O’,如果和边界上的点联系不到一起,那么就是'X'
    row = board.size(), col = board[0].size();
    int dummy_node = row * col + 10;
    init(dummy_node + 5);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            if (board[i][j] == 'O') {
                if (i == 0 || i == row - 1 || j == 0 || j == col - 1) {
                    merge(node(i, j), dummy_node);
                } else {
                    for (int k = 0; k < 4; k++) {
                        int nx = i + dx[k], ny = j + dy[k];
                        if (check(nx, ny) && board[nx][ny] == 'O') {
                            merge(node(i, j), node(nx, ny));
                        }
                    }
                }
            }
        }
    }
    // 检查是否和dummy_node是一组的,如果是就变成'O',否则变成'X'
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            if (find(node(i, j)) == find(dummy_node)) {
                board[i][j] = 'O';
            } else {
                board[i][j] = 'X';
            }
        }
    }
}
}; ```
