130. 被围绕的区域
给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。

找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

示例:

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'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
运行结果
图片说明
解题思路
利用并查集的思想
将所有边缘上的O的父亲置为虚拟节点dimon
然后遍历其他的O,如果将其与其四周的O连通----使得与边缘的O相连的O的父亲也是dimon
这样再次遍历,只要父亲不是虚拟节点的O均置为X
java代码

class Solution {
    public void solve(char[][] board) {
        int m=board.length;
        if(m == 0) return;
        int n=board[0].length;
        UF uf=new UF(m*n+1);
        int domin=m*n;
        //左右边界的0和虚拟节点合并
        for(int i=0;i<m;i++){
            if(board[i][0]=='O'){
                uf.union(i*n,domin);
            }
            if(board[i][n-1]=='O'){
                uf.union(i*n+n-1,domin);
            }
        }
        //上下边界的0和虚拟节点合并
        for(int i=0;i<n;i++){
            if(board[0][i]=='O'){
                uf.union(i,domin);
            }
            if(board[m-1][i]=='O'){
                uf.union(n*(m-1)+i,domin);
            }
        }
        // 方向数组 d 是上下左右搜索的常用手法
        int[][] d = new int[][]{{1,0}, {0,1}, {0,-1}, {-1,0}};
        for(int i=1;i<m-1;i++){
            for(int j=1;j<n-1;j++){
                if(board[i][j]=='O'){
                    //将其与四周的O连通
                    for(int k=0;k<4;k++){
                        int x=i+d[k][0];
                        int y=j+d[k][1];
                        if(board[x][y]=='O'){
                            uf.union(x*n+y,i*n+j);
                        }
                    }
                }
            }
        }
        // 所有不和 dummy 连通的 O,都要被替换
        for(int i=1;i<m-1;i++){
            for(int j=1;j<n-1;j++){
                if(board[i][j]=='O' &&!uf.getconnected(i*n+j,domin)){
                    board[i][j]='X';
                }
            }
        }
    }
    class UF{
        private int[] parent;
        private int[] size;
        private int count;

        public UF(int n){
            parent=new int[n];
            size=new int[n];
            count=n;
            for(int i=0;i<n;i++){
                parent[i]=i;
                size[i]=1;
            }
        }

        public void union(int a,int b){
            int roota=find(a);
            int rootb=find(b);
            if(roota == rootb) return;
            if(size[roota]>size[rootb]){
                parent[rootb]=roota;
                size[roota]+=size[rootb];
            }
            else{
                parent[roota]=rootb;
                size[rootb]+=size[roota];
            }
        }

        public int find(int x){
            while(parent[x] != x){
                parent[x]=parent[parent[x]];
                x=parent[x];
            }
            return x;
        }

        public boolean getconnected(int a,int b){
            int roota=find(a);
            int rootb=find(b);
            return roota==rootb;
        }

        public int getcount(){
            return count;
        }
    }
}