130. Surrounded Regions

Posted 我的名字叫周周

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了130. Surrounded Regions相关的知识,希望对你有一定的参考价值。

    /*
     * 130. Surrounded Regions
     * 2016-4-3 by Mingyang
     * union 什么:所有从边界可达的O元素union在一起
     * union 目的:union完成后那些没有在边界可达O集合中的O是需要翻转的
     */
    public void solve(char[][] board) {
        if (board == null || board.length == 0 || board[0].length == 0)
            return;
        int rows = board.length, cols = board[0].length;
        int oRoot = rows * cols;
        initUnionFind(rows * cols);
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (board[i][j] == ‘X‘) continue;
                int curr = i * cols + j;
                if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {
                    union(curr, oRoot);
                } else {
                    if (j + 1 < cols && board[i][j + 1] == ‘O‘)
                        union(curr, i * cols + j + 1);
                    if (j - 1 >= 0 && board[i][j - 1] == ‘O‘)
                        union(curr, i * cols + j - 1);
                    if (i + 1 < rows && board[i + 1][j] == ‘O‘)
                        union(curr, (i + 1) * cols + j);
                    if (i - 1 >= 0 && board[i - 1][j] == ‘O‘)
                        union(curr, (i - 1) * cols + j);
                }
            }
        }
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (board[i][j] == ‘O‘ && find(i * cols + j) != oRoot) {
                    board[i][j] = ‘X‘;
                }
            }
        }
    }
    int[] s;
    int[] rank;
    private void initUnionFind(int n) {
        s = new int[n + 1];
        rank = new int[n + 1];
        for (int i = 0; i <= n; i++)
            s[i] = i;
        rank[n] = n + 1;
    }
    private int find(int p) {
        if (s[p] == p) return p;
        else return s[p] = find(s[p]);
    }
    private void union(int p, int q) {
        int pRoot = find(p), qRoot = find(q);
        if (pRoot == qRoot) return;
        if (rank[pRoot] < rank[qRoot]) {//保证小的树在大的下面
            s[pRoot] = qRoot;
        } else {
            if (rank[pRoot] == rank[qRoot])
                rank[pRoot]++;
            s[qRoot] = pRoot;
        }
    }
    /*
     * 这道题目也可以不用Union Find来做,
     * 这个题目用到的方法是图形学中的一个常用方法:Flood fill算法,
     * 其实就是从一个点出发对周围区域进行目标颜色的填充。背后的思想就是把一个矩阵看成一个图的结构,
     * 每个点看成结点,而边则是他上下左右的相邻点,然后进行一次广度或者深度优先搜索。
     * 接下来我们看看这个题如何用Flood fill算法来解决。首先根据题目要求,边缘上的‘O‘是不需要填充的,
     * 所以我们的办法是对上下左右边缘做Flood fill算法,把所有边缘上的‘O‘都替换成另一个字符,比如‘#‘。
     * 接下来我们知道除去被我们换成‘#‘的那些顶点,剩下的所有‘O‘都应该被替换成‘X‘,而‘#‘那些最终应该是还原成‘O‘,
     * 如此我们可以做最后一次遍历,然后做相应的字符替换就可以了。复杂度分析上,我们先对边缘做Flood fill算法,
     * 因为只有是‘O‘才会进行,而且会被替换成‘#‘,所以每个结点改变次数不会超过一次,因而是O(m*n)的复杂度,
     * 最后一次遍历同样是O(m*n),所以总的时间复杂度是O(m*n)。
     * 空间上就是递归栈(深度优先搜索)或者是队列(广度优先搜索)的空间,
     * 同时存在的空间占用不会超过O(m+n)(以广度优先搜索为例,每次队列中的结点虽然会往四个方向拓展,
     * 但是事实上这些结点会有很多重复,假设从中点出发,可以想象最大的扩展不会超过一个菱形,也就是n/2*2+m/2*2=m+n,所以算法的空间复杂度是O(m+n))。
     */
    public void solve1(char[][] board) {
        if(board==null || board.length<=1 || board[0].length<=1)
            return;
        for(int i=0;i<board[0].length;i++)
        {
            fill(board,0,i);
            fill(board,board.length-1,i);
        }
        for(int i=0;i<board.length;i++)
        {
            fill(board,i,0);
            fill(board,i,board[0].length-1);
        }
        for(int i=0;i<board.length;i++)
        {
            for(int j=0;j<board[0].length;j++)
            {
                if(board[i][j]==‘O‘)
                    board[i][j]=‘X‘;
                else if(board[i][j]==‘#‘)
                    board[i][j]=‘O‘;                
            }
        }
    }
    private void fill(char[][] board, int i, int j)
    {
        if(board[i][j]!=‘O‘)
            return;
        board[i][j] = ‘#‘;
        LinkedList<Integer> queue = new LinkedList<Integer>();
        int code = i*board[0].length+j;
        queue.offer(code);
        while(!queue.isEmpty())
        {
            code = queue.poll();
            int row = code/board[0].length;
            int col = code%board[0].length;
            if(row>0 && board[row-1][col]==‘O‘)
            {
                queue.offer((row-1)*board[0].length+col);
                board[row-1][col]=‘#‘;
            }
            if(row<board.length-1 && board[row+1][col]==‘O‘)
            {
                queue.offer((row+1)*board[0].length+col);
                board[row+1][col]=‘#‘;
            }
            if(col>0 && board[row][col-1]==‘O‘)
            {
                queue.offer(row*board[0].length+col-1);
                board[row][col-1]=‘#‘;
            }
            if(col<board[0].length-1 && board[row][col+1]==‘O‘)
            {
                queue.offer(row*board[0].length+col+1);
                board[row][col+1]=‘#‘;
            }            
        }
    }
    /*
     * 小结:最近一直在做关于图的BFS的问题,现在已经很明了,就是对于一个节点,放入queue,然后弹出来看邻居
     * 现在问题在于如何把横纵坐标当成一个node,这就是我们这里 int code = i*board[0].length+j;这个打包的过程
     * 这样取出来的时候可以分别知道xy的值
     */

 

以上是关于130. Surrounded Regions的主要内容,如果未能解决你的问题,请参考以下文章

130. Surrounded Regions

130. Surrounded Regions

130. Surrounded Regions

130. Surrounded Regions

130. Surrounded Regions

130. Surrounded Regions