[LintCode] Surrounded Regions
Posted Push your limit!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[LintCode] 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.
Have you met this question in a real interview?
Yes
Example
X X X X
X O O X
X X O X
X O X X
After capture all regions surrounded by ‘X‘
, the board should be:
X X X X
X X X X
X X X X
X O X X
Solution 1. BFS, O(n * m) runtime, O(n * m) space
For each unvisited cell of ‘O‘, do a bfs and add all connected && unvisited cells of ‘O‘ to a list. If at any point, we determine that a cell of ‘O‘ is on one of the four edges of the board,
mark the flag surrounded to false as this whole list of ‘O‘s are not surrounded by ‘X‘. Otherwise, set it to true.
For each list, if the flag surrounded is true, change all the cells in this list to ‘X‘.
Runtime analysis: each cell is visited at most two times, first time for all cells, second time for cells that are ‘O‘ and surrounded by ‘X‘, so O(n * m).
This solution is pretty straightforward, but it must use extra O(n * m) memory to keep track if a cell has been visited and save all connected cells of ‘O‘.
1 public class Solution { 2 private class Point { 3 int x, y; 4 Point(int x, int y){ 5 this.x = x; 6 this.y = y; 7 } 8 } 9 public void surroundedRegions(char[][] board) { 10 if(board == null || board.length == 0 || board[0].length == 0){ 11 return; 12 } 13 int n = board.length, m = board[0].length; 14 boolean[][] visited = new boolean[n][m]; 15 16 for(int i = 0; i < n; i++){ 17 for(int j = 0; j < m; j++){ 18 if(visited[i][j] == false && board[i][j] == ‘O‘){ 19 ArrayList<Point> points = new ArrayList<Point>(); 20 if(bfsHelper(board, i, j, points, visited)){ 21 for(int k = 0; k < points.size(); k++){ 22 board[points.get(k).x][points.get(k).y] = ‘X‘; 23 } 24 } 25 } 26 } 27 } 28 } 29 private boolean bfsHelper(char[][] board, int i, int j, 30 ArrayList<Point> points, 31 boolean[][] visited){ 32 boolean surrounded = true; 33 Queue<Point> queue = new LinkedList<Point>(); 34 Point newP = new Point(i, j); 35 queue.add(newP); 36 visited[i][j] = true; 37 points.add(newP); 38 int[] deltaX = {-1, 0, 1, 0}; 39 int[] deltaY = {0, 1, 0, -1}; 40 41 while(queue.isEmpty() == false){ 42 Point curr = queue.poll(); 43 for(int dir = 0; dir < 4; dir++){ 44 int x = curr.x + deltaX[dir]; 45 int y = curr.y + deltaY[dir]; 46 //if a ‘O‘ has out of bound neighbors, it means this ‘O‘ is not 47 //surrounded. 48 if(isValidPoint(board, x, y) == false){ 49 surrounded = false; 50 } 51 else if(board[x][y] == ‘O‘ && visited[x][y] == false){ 52 newP = new Point(x, y); 53 queue.add(newP); 54 visited[x][y] = true; 55 points.add(newP); 56 } 57 } 58 } 59 return surrounded; 60 } 61 private boolean isValidPoint(char[][] board, int i, int j){ 62 return !(i < 0 || i >= board.length || j < 0 || j >= board[0].length); 63 } 64 }
Solution 2. BFS, O(n * m) runtime, with a better space complexity on average, still O(n * m) space for the queue used in bfs in the worst case
If a cell is ‘O‘ and not surrounded by ‘X‘, it means this cell must be connected via a bunch of other ‘O‘s to a ‘O‘ that is on the edge of the board.
Solution 1 starts from inside and try to hit the edge to determine if a group of connected Os are surrounded by X or not.
Instead, we can try to solve this problem in a reversed fashion. If we starts at Os at the edges and do bfs on connected Os toward the inside of the board,
we can find all connected Os that are NOT surrounded by X. The benefit of this reverse is that we can change the Os to Ws along the way to mark that
these cells are not surrounded by X. After we are done with all bfs, we do a final iteration of the board and change all Ws to Os and all non Ws to Xs.
This is correct since Os that are surround by X is not reachable from the edgy Os and will stay as Os after the bfs. Marking Ws on the fly also save
us from using an extra 2D array to track if a cell has been visited. A visited O will be changed to W and it will not be visited again.
1 public class Solution { 2 public void surroundedRegions(char[][] board) { 3 if(board == null || board.length == 0 || board[0].length == 0) { 4 return; 5 } 6 int n = board.length; 7 int m = board[0].length; 8 for(int i = 0; i < n; i++) { 9 bfsFromEdgeOfBoard(board, i, 0); 10 bfsFromEdgeOfBoard(board, i, m - 1); 11 } 12 for(int j = 0; j < m; j++) { 13 bfsFromEdgeOfBoard(board, 0, j); 14 bfsFromEdgeOfBoard(board, n - 1, j); 15 } 16 for(int i = 0; i < n; i++) { 17 for(int j = 0; j < m; j++) { 18 if(board[i][j] == ‘W‘) { 19 board[i][j] = ‘O‘; 20 } 21 else { 22 board[i][j] = ‘X‘; 23 } 24 } 25 } 26 } 27 private void bfsFromEdgeOfBoard(char[][] board, int row, int col) { 28 if(board[row][col] != ‘O‘) { 29 return; 30 } 31 int[] deltaX = {-1, 0, 1, 0}; 32 int[] deltaY = {0, 1, 0, -1}; 33 Queue<Integer> qx = new LinkedList<Integer>(); 34 Queue<Integer> qy = new LinkedList<Integer>(); 35 qx.add(row); 36 qy.add(col); 37 board[row][col] = ‘W‘; 38 39 while(!qx.isEmpty()) { 40 int cx = qx.poll(); 41 int cy = qy.poll(); 42 for(int dir = 0; dir < 4; dir++) { 43 int nx = cx + deltaX[dir]; 44 int ny = cy + deltaY[dir]; 45 if(isInBound(board, nx, ny) && board[nx][ny] == ‘O‘) { 46 board[nx][ny] = ‘W‘; 47 qx.add(nx); 48 qy.add(ny); 49 } 50 } 51 } 52 } 53 private boolean isInBound(char[][] board, int row, int col) { 54 return row >= 0 && row < board.length && col >= 0 && col < board[0].length; 55 } 56 }
Solution 3. Union Find, O(n * m) runntime, O(n * m) space
1. write a UnionFind class that supports finding root and connect roots at O(1) time.
2. for each unvisited O, connect its neighboring unvisited Os. Make sure when connecting roots, always make edge cells of O as the new root if possible.
3. after iterating the whole board at step 2, we get a balanced union find data structure that contains all cells. The O cells‘ roots are also updated to reflect if
they belong in the same union. Check each O cell to see if it has a edge cell O as its root, if it does, do nothing; if it does not, change it from O to X.
1 public class Solution { 2 private class UnionFind { 3 private int[] father = null; 4 private int row = 0; 5 private int col = 0; 6 public UnionFind(int n, int m){ 7 row = n; 8 col = m; 9 father = new int[n * m]; 10 for(int i = 0; i < n * m; i++){ 11 father[i] = i; 12 } 13 } 14 public int find(int x){ 15 if(father[x] == x){ 16 return x; 17 } 18 return father[x] = find(father[x]); 19 } 20 public void connect(int a, int b){ 21 int root_a = find(a); 22 int root_b = find(b); 23 if(root_a != root_b){ 24 if(ifRootOnMatrixOutEdge(row, col, root_a) == true){ 25 father[root_b] = root_a; 26 } 27 else{ 28 father[root_a] = root_b; 29 } 30 } 31 } 32 } 33 public void surroundedRegions(char[][] board) { 34 if(board == null || board.length == 0 || board[0].length == 0){ 35 return; 36 } 37 int n = board.length; 38 int m = board[0].length; 39 UnionFind uf = new UnionFind(n, m); 40 boolean[][] visited = new boolean[n][m]; 41 int[] deltaX = {-1, 0, 1, 0}; 42 int[] deltaY = {0, 1, 0, -1}; 43 for(int i = 0; i < n; i ++){ 44 for(int j = 0; j < m; j++){ 45 if(board[i][j] == ‘O‘ && visited[i][j] == false){ 46 for(int dir = 0; dir < 4; dir++){ 47 int x = i + deltaX[dir]; 48 int y = j + deltaY[dir]; 49 if(isValidPoint(board, x, y) && board[x][y] == ‘O‘ && 50 visited[x][y] == false){ 51 uf.connect(i * m + j, x * m + y); 52 } 53 } 54 visited[i][j] = true; 55 } 56 57 } 58 } 59 for(int i = 0; i < n; i++){ 60 for(int j = 0; j < m; j++){ 61 if(board[i][j] == ‘O‘ && !ifRootOnMatrixOutEdge(n, m, uf.find(i * m + j))){ 62 board[i][j] = ‘X‘; 63 } 64 } 65 } 66 } 67 private boolean ifRootOnMatrixOutEdge(int rowNum, int colNum, int rootIdx){ 68 return (rootIdx >= 0 && rootIdx <= colNum - 1 69 || rootIdx >= (rowNum - 1) * colNum && rootIdx <= rowNum * colNum - 1 70 || rootIdx % colNum == 0 71 || rootIdx % colNum == colNum - 1); 72 } 73 private boolean isValidPoint(char[][] board, int i, int j){ 74 return !(i < 0 || i >= board.length || j < 0 || j >= board[0].length); 75 } 76 }
Related Problems
Nearest Exit
Connecting Graph
Number of Islands II
Number of Islands
以上是关于[LintCode] Surrounded Regions的主要内容,如果未能解决你的问题,请参考以下文章
[LintCode] Surrounded Regions 包围区域