LeetCode130. 被围绕的区域 Surrounded Regions(Java)

LeetCode 130. 被围绕的区域 Surrounded Regions(Java)

##DFS##, ##BFS##, ##Union Find##

泛洪算法 O ( n 2 ) O(n^2) O(n2)

采用逆向思维,将所有边界上的O采用Flood Fill算法标记其连通域,并做标记#

全图遍历完后,对于board中所有字符不为#的字符,如果为O,即代表不与边界的O(遍历后改为#)相连,因此被X包围,改为X

采用int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1}标记即将要遍历的方向

class Solution {
    int n, m;
    int[] dx = {-1, 0, 1, 0};
    int[] dy = {0, 1, 0, -1};


    public void solve(char[][] board) {
        n = board.length;
        if (n == 0) return;
        m = board[0].length;

        for (int i = 0; i < m; i ++) {
            if (board[0][i] == 'O') {
                dfs(board, 0, i);
            }
            if (board[n - 1][i] == 'O') {
                dfs(board, n - 1, i);
            }
        }
        
        for (int i = 0; i < n; i ++) {
            if (board[i][0] == 'O') {
                dfs(board, i, 0);
            }
            if (board[i][m - 1] == 'O') {
                dfs(board, i, m - 1);
            }
        }

        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                if (board[i][j] == '#') {
                    board[i][j] = 'O';
                } else {
                    board[i][j] = 'X';
                }
            }
        }
    }

    public void dfs(char[][] board, int x, int y) {
        board[x][y] = '#';
        for (int i = 0; i < 4; i ++) {
            int xx = x + dx[i];
            int yy = y + dy[i];
            if (xx >= 0 && xx < n && yy >= 0 && yy < m && board[xx][yy] == 'O') {
                dfs(board, xx, yy);
            }
        }
    }
}

并查集

将边界中的字符为O的区域与dummy结点相连,表示为不被X包围的字符,

并查集中结点数量应该为rows * cols + 1,多出的一个为dummy结点,dummy = rows * cols

遍历所有字符,如果字符board[i][j] == O则,与其上下左右四个方向的O 字符向联通

最后遍历整个图形,所有与dummy结点相连的O结点都不是被包围的结点

class Solution {
    public class UnionFind {
        int[] p = new int[100010];
        int n;

        public void init(int n) {
            this.n = n;
            for (int i = 0; i < n; i ++) {
                p[i] = i;
            }
        }

        public int find(int x) {
            if (x != p[x]) p[x] = find(p[x]);
            return p[x];
        }

        public void union(int x, int y) {
            p[find(y)] = find(x);
            
        }

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

    int n, m;

    public void solve(char[][] board) {
        n = board.length;
        if (n == 0) return;
        m = board[0].length;
        
        UnionFind uf = new UnionFind();
        uf.init(n * m + 1);

        int dummy = n * m;
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                if (board[i][j] == 'O') {
                    if (i == 0 || i == n - 1 || j == 0 || j == m - 1) {
                        uf.union(node(i, j), dummy);
                    } else {
                        if (i - 1 >= 0 && board[i - 1][j] == 'O') {
                            uf.union(node(i - 1, j), node(i, j));
                        }
                        if (i + 1 < n && board[i + 1][j] == 'O') {
                            uf.union(node(i + 1, j), node(i, j));
                        }
                        if (j - 1 >= 0 && board[i][j - 1] == 'O') {
                            uf.union(node(i, j - 1), node(i, j));
                        }
                        if (j + 1 < m && board[i][j + 1] == 'O') {
                            uf.union(node(i, j + 1), node(i, j));
                        }
                    }
                }
            }
        }

        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                if (uf.isConnected(node(i, j), dummy)) {
                    board[i][j] = 'O';
                } else {
                    board[i][j] = 'X';
                }
            }
        }

    }

    public int node(int x, int y) {
        return x * m + y; 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值