130. Surrounded Regions

这是一道Acceptance不到20%的Medium题。通常这种情况就是有需要细心考虑的边界条件或者递归终止条件。
这题思路的话很容易想,从外围找O,找到了就用DFS或者BFS之类的把都是O的neighbor赋值成Y。然后扫两遍,把O变成X,Y变回O。

主要看看DFS部分吧,比较典型的floodfill。注意终止条件写法。
另外网上有很多用用QUEUE实现了BFS,也该写写的,今天太jb累了,真的,在公司写了一天胶水代码,困的一B。睡觉了。

public class Solution {

    public void solve(char[][] board) {
        if (board == null || board.length == 0) return;
        int row = board.length;
        int col = board[0].length;
        for (int i = 0; i < row; i++) {
            dfs(board, i, 0, row, col);
            if (col > 1)
                //这样的话只有一列的情况不用单独处理了
                dfs(board, i, col - 1, row, col);
        }
        //这里可以掐头去尾
        for (int i = 1; i < col - 1; i++) {
            dfs(board, 0, i, row, col);
            if (row > 1)
                dfs(board, row - 1, i , row, col);
        }
        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] == 'Y') {
                    board[i][j] = 'O';
                }
            }
    }

    private void dfs(char[][] board, int i, int j, int row, int col) {
        if (board[i][j] == 'O') {
            board[i][j] = 'Y';
//        if (i < 0 || i > row - 1 || j < 0 || j > col - 1) return;
            if (i - 1 > 0) dfs(board, i - 1, j, row, col);
            if (i + 1 < row) dfs(board, i + 1, j, row, col);
            if (j - 1 > 0) dfs(board, i, j - 1, row, col);
            if (j + 1 < col) dfs(board, i, j + 1, row, col);
        }
    }
}

DFS,BFS可以多搜几种解法看看,比如下面的ref里的几种;但是我看了很多种解法,只有上面贴的这种在检查下一次dfs是否满足的写法才勉强AC(估计速度也是很慢),其他的都会stackOverFlow,我一开始觉得是哪里有逻辑问题,因为不AC的话一般是TLE啊,这题为什么是SOF呢。。。看了http://blog.csdn.net/ChilseaSai/article/details/50375111 之后明白了,就是典型的递归层数过深产生的啊。。每一次递归都是一个栈,Leetcode给出了一些非常屌的testcase,长达几KB的矩阵。。我也是醉了:

HUGE MATRIX!

所以,同样是DFS,在下一次运行开始之前检查,和利用终止条件检查,前者效率会高于后者(前者从本层就阻止了进入下一层DFS,后者是进入下一层DFS再return)。另外,对于数据量大的testcase,用BFS。

那如果不考虑那么大的test case,这题的dfs部分还可以这么写:

    private void dfs(char[][] board, int x, int y, int row, int col) {
        if (x >= 0 &&  x < row && y >=0 && y 

或者这么写:

    private void dfs(char[][] board, int i, int j, int row, int col) {
        if (i < 0 || i >= row || j < 0 || j >= col || board[i][j] != 'O') return;
        board[i][j] = 'Y';
        dfs(board, i - 1, j, row, col);
        dfs(board, i + 1, j, row, col);
        dfs(board, i, j - 1, row, col);
        dfs(board, i, j + 1, row, col);
    }

总之,能终止递归就可以了。

用BFS的话可以这么写:

    public void solve(char[][] board) {
        if (board == null || board.length == 0) return;
        int row = board.length;
        int col = board[0].length;
        for (int i = 0; i < row; i++) {
            if (board[i][0] == 'O')
                bfs(board, i, 0, row, col);
            if (col > 1)
                if (board[i][col-1] == 'O')
                    //这样的话只有一列的情况不用单独处理了
                    bfs(board, i, col - 1, row, col);
        }
        //这里可以掐头去尾
        for (int i = 1; i < col - 1; i++) {
            if (board[0][i] == 'O')
                bfs(board, 0, i, row, col);
            if (row > 1)
                if (board[row-1][i] == 'O')
                    bfs(board, row - 1, i, row, col);
        }
        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] == 'Y') {
                    board[i][j] = 'O';
                }
            }
    }

    private void bfs(char[][] board, int i, int j, int row, int col) {
        //泛型只能有一个参数,所以这里用了Pair保存坐标(也可用余数和商来解析,可参考http://blog.csdn.net/ChilseaSai/article/details/50375111)
        LinkedList queue = new LinkedList<>();
        Pair pair = new Pair(i, j);
        queue.add(pair);
        while (!queue.isEmpty()) {
            Pair p = queue.poll();
            int x = p.x;
            int y = p.y;
            //因为floodfill向四个方向扩散,所以可能回到刚才蔓延过的地方;如果不加这句,提交的时候会TLE
            if (board[x][y] == 'Y') continue;
            if (board[x][y] == 'O') {
                board[x][y] = 'Y';
            }

            if (x - 1 >= 0 && board[x - 1][y] == 'O') {
                queue.add(new Pair(x - 1, y));
            }
            if (x + 1 < row && board[x + 1][y] == 'O') {
                queue.add(new Pair(x + 1, y));
            }
            if (y - 1 >= 0 && board[x][y - 1] == 'O') {
                queue.add(new Pair(x, y - 1));
            }
            if (y + 1 < col && board[x][y + 1] == 'O') {
                queue.add(new Pair(x, y + 1));
            }
        }
    }

    class Pair {
        int x;
        int y;
        Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

再稍微提一下,遍历四个边的方法还可以这么写:

    //对所有在边上的O节点进行BFS  
        for(int i=0;i

参考的是这里,复杂度是一样的都是O(m*n)。

另外,本题还可以用并查集来实现,leetcode的discussion里有。

http://blog.sina.com.cn/s/blog_b9285de20101j1dt.html
http://www.cnblogs.com/guyufei/p/3448824.html
http://blog.csdn.net/ChilseaSai/article/details/50375111

你可能感兴趣的:(130. Surrounded Regions)