思路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';}}}}
}; ```
