力扣每日一题130:被围绕的区域

题目

中等

相关标签

相关企业

给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

示例 1:

输入:board = [["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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

示例 2:

输入:board = [["X"]]
输出:[["X"]]

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 200
  • board[i][j] 为 'X' 或 'O'

通过次数 285.7K

提交次数 614.4K

通过率 46.5%

方法一:并查集

利用并查集,将相邻的相同字母视为一个连通集。边界上的'O'视为同一个集,易得,不与边界上的'O'相邻的'O'即为被围绕的区域。

下面是某位大佬的java代码

class UnionFind {
    int[] parents;

    public UnionFind(int totalNodes) {
        parents = new int[totalNodes];
        for (int i = 0; i < totalNodes; i++) {
            parents[i] = i;
        }
    }
		// 合并连通区域是通过find来操作的, 即看这两个节点是不是在一个连通区域内.
    void union(int node1, int node2) {
        int root1 = find(node1);
        int root2 = find(node2);
        if (root1 != root2) {
            parents[root2] = root1;
        }
    }

    int find(int node) {
        while (parents[node] != node) {
            // 当前节点的父节点 指向父节点的父节点.
            // 保证一个连通区域最终的parents只有一个.
            parents[node] = parents[parents[node]];
            node = parents[node];
        }

        return node;
    }

    boolean isConnected(int node1, int node2) {
        return find(node1) == find(node2);
    }
}
class Solution {
    int rows;
    int cols;
    public void solve(char[][] board) {
        if (board == null || board.length == 0)
            return;

        rows = board.length;
        cols = board[0].length;

        // 用一个虚拟节点, 边界上的O 的父节点都是这个虚拟节点
        UnionFind uf = new UnionFind(rows * cols + 1);
        int dummyNode = rows * cols;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (board[i][j] == 'O') {
                    // 遇到O进行并查集操作合并
                    if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {
                        // 边界上的O,把它和dummyNode 合并成一个连通区域.
                        uf.union(node(i, j), dummyNode);
                    } else {
                        // 和上下左右合并成一个连通区域.
                        if (i > 0 && board[i - 1][j] == 'O')
                            uf.union(node(i, j), node(i - 1, j));
                        if (i < rows - 1 && board[i + 1][j] == 'O')
                            uf.union(node(i, j), node(i + 1, j));
                        if (j > 0 && board[i][j - 1] == 'O')
                            uf.union(node(i, j), node(i, j - 1));
                        if (j < cols - 1 && board[i][j + 1] == 'O')
                            uf.union(node(i, j), node(i, j + 1));
                    }
                }
            }
        }

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (uf.isConnected(node(i, j), dummyNode)) {
                    // 和dummyNode 在一个连通区域的,那么就是O;
                    board[i][j] = 'O';
                } else {
                    board[i][j] = 'X';
                }
            }
        }
    }
    int node(int i, int j) {
        return i * cols + j;
    }
    
}

方法二:深度优先搜索

前面提到,不与边界的'O'连通的'O'即为被包围的区域。所以我们可以以四条边上的'O'为起点搜索,将与边界'O'连通的'O'做个标记,随后有标记的'O'就改回'O',没有标记的'O'就变成'X'。

class Solution {
public:
    void dfs(vector<vector<char>>& board,int x,int y,int n,int m)
    {
        if(x<0||x>=n||y<0||y>=m||board[x][y]!='O')
        {
            return;
        }
        board[x][y]='Y';
        dfs(board,x+1,y,n,m);
        dfs(board,x,y-1,n,m);
        dfs(board,x-1,y,n,m);
        dfs(board,x,y+1,n,m);
    }
    void solve(vector<vector<char>>& board) {
        int n=board.size();
        if(n==1) return;
        int m=board[0].size();
        if(m==1) return;
        for(int i=0;i<n;i++)
        {
            dfs(board,i,0,n,m);
            dfs(board,i,m-1,n,m);
        }
        for(int j=1;j<m-1;j++)
        {
            dfs(board,0,j,n,m);
            dfs(board,n-1,j,n,m);
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(board[i][j]=='Y')
                board[i][j]='O';
                else if(board[i][j]=='O')
                board[i][j]='X';
            }
        }
    }
};

相关推荐

  1. 130. 围绕区域

    2024-06-09 15:50:06       37 阅读
  2. 【DFS】130.围绕区域

    2024-06-09 15:50:06       39 阅读
  3. 每日2397列覆盖最多行数

    2024-06-09 15:50:06       32 阅读
  4. 2024.1.4每日——列覆盖最多行数

    2024-06-09 15:50:06       38 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-09 15:50:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-09 15:50:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-09 15:50:06       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-09 15:50:06       20 阅读

热门阅读

  1. 爬山算法的详细介绍

    2024-06-09 15:50:06       8 阅读
  2. MySQL和MariaDB的对比和选型

    2024-06-09 15:50:06       10 阅读
  3. LLMs,即大型语言模型

    2024-06-09 15:50:06       11 阅读
  4. 深度学习中自监督学习

    2024-06-09 15:50:06       11 阅读
  5. Jenkins 内置变量 和变量作用域

    2024-06-09 15:50:06       11 阅读
  6. 为什么要选择AWS?AWS的优势有哪些?

    2024-06-09 15:50:06       11 阅读
  7. SASS基础知识

    2024-06-09 15:50:06       10 阅读
  8. linux的sed

    2024-06-09 15:50:06       8 阅读
  9. No signature found in package of version 2 or newer for package

    2024-06-09 15:50:06       6 阅读
  10. 进程和线程

    2024-06-09 15:50:06       7 阅读