Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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'的格子再处理一次,时间复杂度是一致的。但是后一种省去了很多判断和空间。

//20181003

同样的方法,重写一遍。主要是提炼出一个helper方法。

class Solution {
    public void solve(char[][] board) {
        if (board.length == 0) {
            return;
        }
        
        int[][] visited = new int[board.length][board[0].length];
        
        for (int i = 0; i < board.length; i ++) {
            for (int j = 0; j < board[0].length; j++) {
                if ((i == 0 || j == 0 || i == board.length - 1 || j == board[0].length - 1) && board[i][j] == 'O') {
                    visited[i][j] = 1;
                    bfs(board, new int[]{i, j}, visited);                    
                }
            }
        }
        
        for (int i = 0; i < board.length; i ++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == 'O' && visited[i][j] == 0) {
                    board[i][j] = 'X';
                }
            }
        }
        
        return;
    }
    
    public void bfs(char[][] board, int[] start, int[][] visited) {
        Queue<int[]> queue = new LinkedList<int[]>();
        queue.offer(new int[]{start[0], start[1]});
        while (queue.size() > 0) {
            int[] coordinate = queue.poll();
            
            int x = coordinate[0] - 1;
            int y = coordinate[1];            
            helper(queue, board, visited, x, y);
            
            x = coordinate[0] + 1;
            y = coordinate[1];            
            helper(queue, board, visited, x, y);
            
            x = coordinate[0];
            y = coordinate[1] - 1;            
            helper(queue, board, visited, x, y);
            
            x = coordinate[0];
            y = coordinate[1] + 1;            
            helper(queue, board, visited, x, y);
        }
    }
    
    public void helper(Queue<int[]> queue, char[][] board, int[][] visited, int x, int y) {
        if (x >= 0 && x < board.length && y >= 0 && y < board[0].length && board[x][y] == 'O' && visited[x][y] == 0) {
            queue.offer(new int[]{x, y});
            visited[x][y] = 1;
        }
    }
}

 

posted on 2015-04-22 14:09  NickyYe  阅读(272)  评论(0编辑  收藏  举报