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的主要内容,如果未能解决你的问题,请参考以下文章