130-Surrounded Regions

Description

Given a 2D board containing ‘X’ and ‘O’ (the letter O), capture all regions surrounded by ‘X’.

A region is captured by flipping all ‘O’s into ‘X’s in that surrounded region.

Example:

X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

Explanation:

Surrounded regions shouldn’t be on the border, which means that any ‘O’ on the border of the board are not flipped to ‘X’. Any ‘O’ that is not on the border and it is not connected to an ‘O’ on the border will be flipped to ‘X’. Two cells are connected if they are adjacent cells connected horizontally or vertically.

问题描述

给定二维数组, 其中元素为’X’或者’O’, 捕获所有被’X’围住的区域

通过将一个区域中的所有’O’转换为’X’来将一个区域捕获

Example:

X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

解释:

围住的区域不能在边界上, 这意味着任何在边界上的’O’不能被转换为’X’.那些既不在边界上且不与在边界上的’O’相邻的’O’会转换为’X’.相邻的意思是水平或者垂直相连

问题分析

有三种做法, DFS, BFS, 和并查集。核心是从边界上的’O’找出不会被围住的’O’

解法1(BFS)

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

        int rowN = board.length;
        int colN = board[0].length;
        Queue<Point> queue = new LinkedList();

       //get all 'O's on the edge first
        for(int r = 0; r < rowN; r++){
            if(board[r][0] == 'O'){
                board[r][0] = '+';
                queue.add(new Point(r, 0));
            }
            if(board[r][colN-1] == 'O'){
                board[r][colN-1] = '+';
                queue.add(new Point(r, colN - 1));
            }
        }

        for(int c = 0; c < colN; c++){
            if(board[0][c] == 'O'){
                board[0][c] = '+';
                queue.add(new Point(0, c));
            }
            if(board[rowN - 1][c] == 'O'){
                board[rowN - 1][c] = '+';
                queue.add(new Point(rowN - 1, c));
            }
        }

        //BFS for the 'O's, and mark it as '+'
        while(!queue.isEmpty()){
            Point p = queue.poll();
            int row = p.x;
            int col = p.y;
            if(row - 1 >= 0 && board[row-1][col] == 'O'){
                board[row-1][col] = '+';
                queue.add(new Point(row - 1, col));
            }
            if(row + 1 < rowN && board[row+1][col] == 'O'){
                board[row+1][col] = '+';
                queue.add(new Point(row + 1, col));
            }
            if(col - 1 >= 0 && board[row][col - 1] == 'O'){
                board[row][col-1] = '+'; 
                queue.add(new Point(row, col - 1));}
            if(col + 1 < colN && board[row][col + 1] == 'O'){
                board[row][col+1] = '+';
                queue.add(new Point(row, col + 1));
            }                 
        }

        //turn all '+' to 'O', and 'O' to 'X'
        for(int i = 0; i < rowN; i++){
            for(int j = 0; j < colN; j++){
                if(board[i][j] == 'O')  board[i][j] = 'X';
                if(board[i][j] == '+')  board[i][j] = 'O';
            }
        }
    }
}

解法2(并查集)

public class Solution {
    private int m, n;

    private class UnionFind{
        private int[] parent;
        private int[] rank;

        public UnionFind(int n){
            parent = new int[n];
            rank = new int[n];

            for(int i = 0;i < n;i++)    parent[i] = i;
        }
        public int find(int n){
            while(n != parent[n]){
                parent[n] = parent[parent[n]];
                n = parent[n];
            }

            return n;
        }      
        public void union(int i, int j){
            int rooti = find(i);
            int rootj = find(j);

            if(rooti == rootj) return;

            if(rank[rootj] < rank[rooti]){
                parent[rootj] = rooti;
            }else{
                parent[rooti] = rootj;
                if(rank[rooti] == rank[rootj]) rank[rootj]++;
            }
        }
    }

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

        m = board.length;
        n = board[0].length;
        //可以当作标记不会被围住的'O'的集合的钩子
        int dummyNode = m * n;
        UnionFind unionFind = new UnionFind(dummyNode + 1);
        //遍历board, 构建集合
        for(int i = 0; i < m;i++){
            for(int j = 0;j < n;j++){
                if(board[i][j] == 'O'){
                    if(i == 0 || j == 0 || i == m - 1 || j == n - 1){
                        //注意这里
                        unionFind.union(getNode(i, j), dummyNode);
                    }else{
                        if(j - 1 >= 0 && board[i][j - 1] == 'O')  unionFind.union(getNode(i, j), getNode(i, j - 1));
                        if(i - 1 >= 0 && board[i - 1][j] == 'O')  unionFind.union(getNode(i, j), getNode(i - 1, j));
                        if(i + 1 < m && board[i + 1][j] == 'O')   unionFind.union(getNode(i, j), getNode(i + 1, j));
                        if(j + 1 < n && board[i][j + 1] == 'O')   unionFind.union(getNode(i, j), getNode(i, j + 1));
                    }
                }
            }
        }

        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){
                if(board[i][j] == 'O'){
                    if(unionFind.find(getNode(i, j)) == unionFind.find(dummyNode)) board[i][j] = 'O';
                    else    board[i][j] = 'X';
                }
            }
        }
    }
    public int getNode(int i, int j){
        return i * n + j;
    }
}

解法3(DFS)

class Solution {
    public void solve(char[][] board) {
        if(board == null || board.length == 0) return;

        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++){
                if(i == 0 || i == board.length - 1 || j == 0 || j == board[0].length - 1){
                    if(board[i][j] == 'O') dfs(i, j, board);
                }
            }
        }
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[0].length; j++){
                if(board[i][j] == '*') board[i][j] ='O';
                else board[i][j] = 'X';
            }
        }

        return;
    }
    private void dfs(int i,int j,char[][] board){
        if(board[i][j] == 'X' || board[i][j] == '*') return;

        board[i][j] = '*';
        if(i + 1 < board.length)    dfs(i + 1, j, board);
        if(i - 1 > 0)   dfs(i - 1, j, board);
        if(j + 1 < board[0].length) dfs(i, j + 1, board);
        if(j - 1 > 0)   dfs(i, j - 1, board);
    }
}
点赞