题目:Given a 2D board containing 'X'
and 'O'
(the letter 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
题意及分析:
给出一个二位矩阵,
若存在'O'组成的区域被‘X’包含,那么将改‘O’区域替换为‘X’。我最开始想到的是,用一个visited[row][col]保存该点是否访问过,然后遍历矩阵,对遇到的非边界、为访问过的‘O’点进行区域查找,将区域用一个List<Integer[]> 保存,若不存在在边界的‘O’,那么该区域满足条件(其实就是图的宽度查找),但是这里用了递归,所以运行代码栈溢出。。。反向思维:从边界的‘O’点开始查找,如果有何边界的‘O’点相连的则不用替换(这里用一个'#'先替换),遍历所有的边界‘O’,最后对遍历一次矩阵,将所有的'O'转化为‘X’,然后在遍历一次将‘#’转回为‘O’,这样可以直接替换,不需要保存可能的值。
内存溢出代码:
public class Solution { public void solve(char[][] board) { int row = board.length; //行数 if(row==0) return; int col=board[0].length; //列数 boolean[][] visited = new boolean[row][col]; for(int i=0;i<row;i++){ for(int j=0;j<col;j++){ List<Integer[]> union = new ArrayList<>(); if((i!=0&&j!=0&&i!=row-1&&j!=col-1)&&(board[i][j]=='O')&&(!visited[i][j])){ //遍历到非边界且未被访问过的'o' union.clear(); // 遍历到一个未被访问的o点,就访问该点能到达的所有'o'点 boolean[] isNeedChange = {true}; //判断该'o'点能达到的区域是否满足要求 findUnion(visited,union,i,j,board,isNeedChange); if(isNeedChange[0]){ //该区域需要改变,那就改变咯 for(int m=0;m<union.size();m++){ Integer[] temp = union.get(m); board[temp[0]][temp[1]] = 'X'; } } } } } } public void findUnion(boolean[][] visited,List<Integer[]> union,int i,int j,char[][] board,boolean[] isNeedChange){ //查找某一个'o'区域 int row = board.length; int col = board[0].length; if(visited[i][j]) return; //该点已经访问过,直接返回 visited[i][j] =true; Integer[] indexs = {i,j}; if(isNeedChange[0]==false) { union.clear(); return; } else { union.add(indexs); } if(i-1>=0&&board[i-1][j]=='O'){ //上 if(i-1==0) isNeedChange[0]=false; //边界点有为'o'的 findUnion(visited,union,i-1,j,board,isNeedChange); } if(i+1<row&&board[i+1][j]=='O'){ //下 if(i+1==row-1) isNeedChange[0]=false; //边界点有为'o'的 findUnion(visited,union,i+1,j,board,isNeedChange); } if(j-1>=0&&board[i][j-1]=='O'){ //左 if(j-1==0) isNeedChange[0]=false; //边界点有为'o'的 findUnion(visited,union,i,j-1,board,isNeedChange); } if(j+1<col&&board[i][j+1]=='O'){ //右 if(j+1==col-1) isNeedChange[0]=false; //边界点有为'o'的 findUnion(visited,union,i,j+1,board,isNeedChange); } } }
AC代码:
public class Solution { public void solve(char[][] board) { int row = board.length; //行数 if(row==0) return; int col=board[0].length; //列数 Queue<Integer[]> queue = new LinkedList<>(); //记录需要被替换的点,初始时是边界的点 for(int i=0;i<col;i++){ if(board[0][i]=='O') { //上边界点为'O',宽度查找 Integer[] index={0,i}; queue.offer(index); } } for(int i=0;i<col;i++){ if(board[row-1][i]=='O') { //下边界有'O' Integer[] index={row-1,i}; queue.offer(index); } } for(int i=1;i<row-1;i++){ //左边界点有’‘ if(board[i][0]=='O') { Integer[] index={i,0}; queue.offer(index); } } for(int i=1;i<row-1;i++){ if(board[i][col-1]=='O') { Integer[] index={i,col-1}; queue.offer(index); } } while(!queue.isEmpty()){ Integer[] index = queue.poll(); int m = index[0],n=index[1]; if(board[m][n]=='O'){ //初次遍历到该点 board[m][n]='#'; //将该点置为'#' if(m>=1&&board[m-1][n]=='O'){ Integer[] temp = {m-1,n}; queue.offer(temp); } if(m<row-1&&board[m+1][n]=='O'){ Integer[] temp = {m+1,n}; queue.offer(temp); } if(n>=1&&board[m][n-1]=='O'){ Integer[] temp = {m,n-1}; queue.offer(temp); } if(n<col-1&&board[m][n+1]=='O'){ Integer[] temp = {m,n+1}; queue.offer(temp); } } } for(int i=0;i<row;i++){ //替换被包含的'O'点 for (int j=0;j<col;j++){ if(board[i][j]=='O') board[i][j]='X'; } } for(int i=0;i<row;i++){ //替换回来 for (int j=0;j<col;j++){ if(board[i][j]=='#') board[i][j]='O'; } } return; } }