一. 这一题也是回溯算法,因为对题目理解不太清楚,所以就直接看大神解法了.
二. 参考
作者:Ac_pipe 链接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/
思路:1. 这道题我们拿到基本就可以确定是图的 dfs、bfs 遍历的题目了。题目中解释说被包围的区间不会存在于边界上,所以我们会想到边界上的 O 要特殊处理,只要把边界上的 O 特殊处理了,那么剩下的 O 替换成 X 就可以了。问题转化为,如何寻找和边界联通的 O.
2. 这时候的 O 是不做替换的。因为和边界是连通的。为了记录这种状态,我们把这种情况下的 O 换成 # 作为占位符,待搜索结束之后,遇到 O 替换为 X(和边界不连通的 O);遇到 #,替换回 O(和边界连通的 O)。
3. 如何寻找和边界联通的O? 从边界出发,对图进行 dfs 和 bfs 即可。这里简单总结下 dfs 和 bfs。
bfs 递归。可以想想二叉树中如何递归的进行层序遍历。 bfs 非递归。一般用队列存储。 dfs 递归。最常用,如二叉树的先序遍历。 dfs 非递归。一般用 stack。
三. dfs递归
//这个没有使用visited数组标记有无使用过这个数.而是改用不同的符号#去标记. class Solution { public: void dfs(vector<vector<char>>& board, int i, int j) { //终止条件,要不超出范围,要不碰到#或者X. if (i >= board.size() || i < 0 || j < 0 || j >= board[0].size() || board[i][j] == '#' || board[i][j] == 'X') return; //边界的标记为特殊的符号. board[i][j] = '#'; 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) { //边界条件. if (board.size() == 0 || board[0].size() == 0) return; int m = board.size(), n = board[0].size(); bool b; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { //遍历数组,先解决边界的O问题. //如果i,j处于边界上,且为O. //则dfs,深度优先搜索. b = (i == 0 || i == m - 1 || j == 0 || j == n - 1); if (b && board[i][j] == 'O') dfs(board, i, j); } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (board[i][j] == '#') board[i][j] = 'O'; else if (board[i][j] == 'O') board[i][j] = 'X'; } } } };四. 继续参考下一个大神的,可以用作回溯的通用模板了.
作者:windliang 链接:https://leetcode-cn.com/problems/surrounded-regions/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-3-6/
1. 解法一是从当前节点做 DFS ,然后看它是否能到达边界的 O。那么我们能不能把思路逆转过来呢?
2. 从边界的 O 做 DFS,然后把遇到的 O 都标记一下,这些 O 就是可以连通到边界的。然后把边界的所有的 O 都做一次 DFS ,把 DFS 过程的中的 O 做一下标记。最后我们只需要遍历节点,把没有标记过的 O 改成 X 就可以了。
3. 标记的话,我们可以用一个 visited 二维数组,把访问过的置为 true .(这是一个技巧)
class Solution { public: //记住,传入数组时一定要传入他的地址,不然值不会改变. void dfs(int i, int j, vector<vector<char>>& board, vector<vector<int>>& visited) { if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size()) return; if (visited[i][j] == 1) return; //如果遇到'X',都不满足条件,则直接返回. if (board[i][j] == 'O') { //将当前坐标设置为1,注意是当前的. visited[i][j] = 1; dfs(i + 1, j, board, visited); dfs(i - 1, j, board, visited); dfs(i, j + 1, board, visited); dfs(i, j - 1, board, visited); } } void solve(vector<vector<char>>& board) { //边界条件. if (board.size() == 0 || board[0].size() == 0) return; int m = board.size(), n = board[0].size(); vector<vector<int>> visited(m, vector<int>(n, 0)); //直接把边界找出来对边界处理. for (int j = 0; j < n; j++) { if (board[0][j] == 'O') dfs(0, j, board, visited); if (board[m - 1][j] == 'O') { dfs(m - 1, j, board, visited); } } for (int i = 0; i < m; i++) { if (board[i][0] == 'O') dfs(i, 0, board, visited); if (board[i][n - 1] == 'O') dfs(i, n - 1, board, visited); } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (visited[i][j] == 1) board[i][j] = 'O'; else if (board[i][j] == 'O') board[i][j] = 'X'; } } } };
