241107-leetcode130

38 阅读3分钟

给你一个 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"]]

思路 本次用并查集不用dfs了

  • 创建一个虚拟节点,把4条边上所有O和该节点关联,
  • 遍历矩阵联通,连接右下节点【因为我们从左到右从上到下遍历,左上方的节点认为已经合并过了】
  • 遍历所有O,看是否和虚拟节点同一个连通图,不是的话就变成X
class Solution {
    int[][] direction = {{1, 0}, {0, 1}};
    int rows;
    int cols;

    //联通类问题,本次用uf解,
    // 1)创建一个虚拟节点,把4条边上所有O和该节点关联,
    //2)遍历矩阵联通,连接右下节点【因为我们从左到右从上到下遍历,左上方的节点认为已经合并过了】
    //3)遍历所有O,看是否和虚拟节点同一个连通图,不是的话就变成X
    public void solve(char[][] board) {
        rows = board.length;
        cols = board[0].length;
        UnionFind unionFind = new UnionFind(cols * rows + 1);

        //虚拟节点连接所有O边缘节点
        int dummyNode = rows * cols;

        // 填写第 1 行和最后一行
        for (int j = 0; j < cols; j++) {
            if (board[0][j] == 'O') {
                unionFind.union(getIndex(0, j), dummyNode);
            }
            if (board[rows - 1][j] == 'O') {
                unionFind.union(getIndex(rows - 1, j), dummyNode);
            }
        }

        // 填写第 1 列和最后一列
        for (int i = 1; i < rows - 1; i++) {
            if (board[i][0] == 'O') {
                unionFind.union(getIndex(i, 0), dummyNode);
            }
            if (board[i][cols - 1] == 'O') {
                unionFind.union(getIndex(i, cols - 1), dummyNode);
            }
        }

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (board[i][j] == 'O') {
                    for (int[] d : direction) {
                        int newX = i + d[0];
                        int newY = j + d[1];
                        if (newX < rows && newY < cols && board[newX][newY] == 'O')
                            unionFind.union(getIndex(newX, newY), getIndex(i, j));
                    }
                }
            }
        }

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (board[i][j] == 'O' && !unionFind.isConnect(getIndex(i, j), dummyNode))
                    board[i][j] = 'X';
            }
        }

    }


    public int getIndex(int x, int y) {
        return x * cols + y;
    }

    public class UnionFind {
        //每个位置的父节点
        int[] parents;

        public UnionFind(int n) {
            parents = new int[n];
            for (int i = 0; i < n; i++) {
                parents[i] = i;
            }
        }

        public int find(int i) {
            while (parents[i] != i) {
                i = parents[i];
            }
            return i;
        }

        public boolean isConnect(int x, int y) {
            return find(x) == find(y);
        }

        public void union(int x, int y) {
            int px = find(x);
            int py = find(y);

            if (px == py)
                return;
            parents[px] = py;
            return;
        }
    }

}

dfs解法


class Solution {
        int[][] direction = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
        public void solve(char[][] board) {
            //想到沿着边dfs所有的O,标记为T,然后遍历把所有的o变为X
            int row = board.length;
            int col = board[0].length;
            boolean[][] visited = new boolean[row][col];

            for(int i = 0; i < row; i++){
                if(board[i][0] == 'O' &&  visited[i][0] == false){
                    dfs(board, visited, i, 0);
                }
                if(board[i][col-1] == 'O' && visited[i][col-1] == false){
                    dfs(board, visited, i, col-1);
                }
            }

            for(int j = 0; j < col; j++){
                if(board[0][j] == 'O' && visited[0][j] == false){
                    dfs(board, visited, 0, j);
                }
                if(board[row-1][j] == 'O' && visited[row-1][j] == false){
                    dfs(board, visited, row-1 , j);
                }
            }

            for(int i = 0; i < row; i++){
                for(int j = 0; j < col; j++){
                    if(board[i][j] == 'O')
                       board[i][j] = 'X';
                }
            }

            for(int i = 0; i < row; i++){
                for(int j = 0; j < col; j++){
                    if(board[i][j] == 'T')
                       board[i][j] = 'O';
                }
            }
            return;
        }

        public void dfs(char[][] board, boolean[][] visited, int row, int col){
            if(!inArea(board, row, col) || board[row][col] != 'O' || visited[row][col]){
                return;
            }

            board[row][col] = 'T';
            visited[row][col] = true;
            for(int i = 0; i < 4; i++){
                dfs(board, visited, direction[i][0]+row, direction[i][1]+col);
            }
            return;
        }

        public boolean inArea(char[][] board, int x, int y) {
            if (y < 0 || y >= board[0].length || x < 0 || x >= board.length)
                return false;
            return true;
        }
    }
    ```