Surrounded Regions

https://leetcode.com/problems/surrounded-regions/

Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'.

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

For 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

解题思路:

这题的tag很重要——breadth first search。如何用广度优先搜索?

遍历整个board,遇到一个'O',就去对他进行广度搜索,上下左右扩展。遇到'O',并且没有visited过的,就将它加入到本次BFS的结果集中,并且将它记录为visited。

一次BFS中,如果有一个'O'在board的边缘,本次BFS的全部元素都不能置为'X'。否则,将它们都置为'X'。

本次BFS结束后,寻找下一个'O',并且没有visited过的,重复上面的过程。

直至board全部遍历结束。

public class Solution {

    public void solve(char[][] board) {

        if(board.length == 0) {

            return;

        }

        //记录已经遍历过的格子

        int[][] visited = new int[board.length][board[0].length];

        //queue的成员是一个{i,j}的数组,记录本次BFS的坐标

        Queue<int []> queue = new LinkedList<int []>();

        for(int i = 0; i < board.length; i++) {

            for(int j = 0; j < board[0].length; j++) {

                if(visited[i][j] == 1) {

                    continue;

                }

                //一次BFS就要BFS全部,如果本次BFS的全部'O'元素都不碰到board的边缘,就将他们全部置为X

                //如果有一个碰到board,全部'O'都不能置为X,但是本次BFS也必须全部结束,并且全部'O'标记为visited,下次BFS不再遍历它们

                boolean valid = true;

                //pathList记录本次BFS全部'O'的坐标,仅当valid==true的时候,将它们都置为'X'

                ArrayList<int []> pathList = new ArrayList<int []>();

                if(board[i][j] == 'O') {

                    queue.offer(new int[]{i, j});

                    pathList.add(new int[]{i, j});

                    visited[i][j] = 1;

                    while(queue.size() > 0) {

                        int[] index = queue.poll();

                        if(index[0] == 0 || index[0] == board.length - 1 || index[1] == 0 || index[1] == board[0].length - 1) {

                            valid = false;

                        }

                        if(index[0] > 0 && board[index[0] - 1][index[1]] == 'O' && visited[index[0] - 1][index[1]] == 0) {

                            queue.offer(new int[]{index[0] - 1, index[1]});

                            pathList.add(new int[]{index[0] - 1, index[1]});

                            visited[index[0] - 1][index[1]] = 1;

                        }

                        if(index[1] > 0 && board[index[0]][index[1] - 1] == 'O' && visited[index[0]][index[1] - 1] == 0) {

                            queue.offer(new int[]{index[0], index[1] - 1});

                            pathList.add(new int[]{index[0], index[1] - 1});

                            visited[index[0]][index[1] - 1] = 1;

                        }

                        if(index[0] < board.length - 1 && board[index[0] + 1][index[1]] == 'O' && visited[index[0] + 1][index[1]] == 0) {

                            queue.offer(new int[]{index[0] + 1, index[1]});

                            pathList.add(new int[]{index[0] + 1, index[1]});

                            visited[index[0] + 1][index[1]] = 1;

                        }

                        if(index[1] < board[0].length - 1 && board[index[0]][index[1] + 1] == 'O' && visited[index[0]][index[1] + 1] == 0) {

                            queue.offer(new int[]{index[0] , index[1] + 1});

                            pathList.add(new int[]{index[0], index[1] + 1});

                            visited[index[0]][index[1] + 1] = 1;

                        }

                    }

                    //本次BFS结束,并且没有'O'碰到board边缘,就将他们都置为'X'

                    if(valid) {

                        for(int[] index : pathList) {

                            board[index[0]][index[1]] = 'X';

                        }

                    }

                }

            }

        }

    }

}

这个解法是AC的,但是时间在500多ms,主流的都在350ms,还是有什么耗时的。后来看到大神也遇到同样的问题,优化了一下。

http://fisherlei.blogspot.sg/2013/03/leetcode-surrounded-regions-solution.html

思路是:因为上面的遍历是对于board按顺序,然后判断有没有'O'在board边缘的。其实我们只要从board的边缘的'O'开始BFS就可以了!寻找从他们可以BFS到的'O',这些'O'都不能置为'X',余下的'O'都可以置为'X'。这个思路和上面的想法完全一致,但是流程上却巧妙很多,避免了很多用来记录的变量。

我把BFS的代码拿出来单独写了一个方法,代码如下:

public class Solution {

    public void solve(char[][] board) {

        if(board.length == 0) {

            return;

        }

        //记录已经遍历过的格子

        int[][] visited = new int[board.length][board[0].length];

        //queue的成员是一个{i,j}的数组,记录本次BFS的坐标

        Queue<int []> queue = new LinkedList<int []>();

        

        //上边框

        for(int i = 0; i < board[0].length; i++) {

            if(visited[0][i] == 0 && board[0][i] == 'O') {

                queue.offer(new int[]{0, i});

                visited[0][i] = 1;

                bfs(board, queue, visited);

            }

        }

        

        //下边框

        for(int i = 0; i < board[0].length; i++) {

            if(visited[board.length - 1][i] == 0 && board[board.length - 1][i] == 'O') {

                queue.offer(new int[]{board.length - 1, i});

                visited[board.length - 1][i] = 1;

                bfs(board, queue, visited);

            }

        }

        

        //左边框

        for(int i = 0; i < board.length; i++) {

            if(visited[i][0] == 0 && board[i][0] == 'O') {

                queue.offer(new int[]{i, 0});

                visited[i][0] = 1;

                bfs(board, queue, visited);

            }

        }

        

        //右边框

        for(int i = 0; i < board.length; i++) {

            if(visited[i][board[0].length - 1] == 0 && board[i][board[0].length - 1] == 'O') {

                queue.offer(new int[]{i, board[0].length - 1});

                visited[i][board[0].length - 1] = 1;

                bfs(board, queue, visited);

            }

        }

        

        //最后,可以从边框的'O'BFS到的'O',都不能置为'X',其余的'O'都置为'X'

        for(int i = 0; i < board.length; i++) {

            for(int j = 0; j < board[0].length; j++) {

                if(visited[i][j] == 0 && board[i][j] == 'O') {

                    board[i][j] = 'X';

                }

            }

        }

    }

    

    public void bfs(char[][] board, Queue<int []> queue, int[][] visited) {

        while(queue.size() > 0) {

            int[] index = queue.poll();

            if(index[0] > 0 && board[index[0] - 1][index[1]] == 'O' && visited[index[0] - 1][index[1]] == 0) {

                queue.offer(new int[]{index[0] - 1, index[1]});

                visited[index[0] - 1][index[1]] = 1;

            }

            if(index[1] > 0 && board[index[0]][index[1] - 1] == 'O' && visited[index[0]][index[1] - 1] == 0) {

                queue.offer(new int[]{index[0], index[1] - 1});

                visited[index[0]][index[1] - 1] = 1;

            }

            if(index[0] < board.length - 1 && board[index[0] + 1][index[1]] == 'O' && visited[index[0] + 1][index[1]] == 0) {

                queue.offer(new int[]{index[0] + 1, index[1]});

                visited[index[0] + 1][index[1]] = 1;

            }

            if(index[1] < board[0].length - 1 && board[index[0]][index[1] + 1] == 'O' && visited[index[0]][index[1] + 1] == 0) {

                queue.offer(new int[]{index[0] , index[1] + 1});

                visited[index[0]][index[1] + 1] = 1;

            }

        }

    }

}

这样一改,时间减到了350ms。

上面两种解法,每个格子都仅仅遍历一次,然后需要置为'X'的格子再处理一次,时间复杂度是一致的。但是后一种省去了很多判断,和空间。

你可能感兴趣的:(round)