• 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的值
         */
  • 相关阅读:
    pycharm中Terminal中运行用例
    python pandas模块简单使用(读取excel为例)
    pytest框架,使用print在控制台输入
    CentOS7配置python3教程
    linux 添加与修改用户归属组
    python 连接oracle基础环境配置方法
    robot framework 接口post请求需要加headers
    unittest中的parameterized参数化
    json格式
    Django_URL
  • 原文地址:https://www.cnblogs.com/zmyvszk/p/5517952.html
Copyright © 2020-2023  润新知