Surrounded Regions -- LeetCode

这个题目用到的方法是图形学中的一个常用方法: 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))。代码如下:
[java]  view plain  copy
  1. public void solve(char[][] board) {  
  2.     if(board==null || board.length<=1 || board[0].length<=1)  
  3.         return;  
  4.     for(int i=0;i<board[0].length;i++)  
  5.     {  
  6.         fill(board,0,i);  
  7.         fill(board,board.length-1,i);  
  8.     }  
  9.     for(int i=0;i<board.length;i++)  
  10.     {  
  11.         fill(board,i,0);  
  12.         fill(board,i,board[0].length-1);  
  13.     }  
  14.     for(int i=0;i<board.length;i++)  
  15.     {  
  16.         for(int j=0;j<board[0].length;j++)  
  17.         {  
  18.             if(board[i][j]=='O')  
  19.                 board[i][j]='X';  
  20.             else if(board[i][j]=='#')  
  21.                 board[i][j]='O';                  
  22.         }  
  23.     }  
  24. }  
  25. private void fill(char[][] board, int i, int j)  
  26. {  
  27.     if(board[i][j]!='O')  
  28.         return;  
  29.     board[i][j] = '#';  
  30.     LinkedList<Integer> queue = new LinkedList<Integer>();  
  31.     int code = i*board[0].length+j;  
  32.     queue.offer(code);  
  33.     while(!queue.isEmpty())  
  34.     {  
  35.         code = queue.poll();  
  36.         int row = code/board[0].length;  
  37.         int col = code%board[0].length;  
  38.         if(row>0 && board[row-1][col]=='O')  
  39.         {  
  40.             queue.offer((row-1)*board[0].length+col);  
  41.             board[row-1][col]='#';  
  42.         }  
  43.         if(row<board.length-1 && board[row+1][col]=='O')  
  44.         {  
  45.             queue.offer((row+1)*board[0].length+col);  
  46.             board[row+1][col]='#';  
  47.         }  
  48.         if(col>0 && board[row][col-1]=='O')  
  49.         {  
  50.             queue.offer(row*board[0].length+col-1);  
  51.             board[row][col-1]='#';  
  52.         }  
  53.         if(col<board[0].length-1 && board[row][col+1]=='O')  
  54.         {  
  55.             queue.offer(row*board[0].length+col+1);  
  56.             board[row][col+1]='#';  
  57.         }              
  58.     }  
  59. }  
可以看到上面代码用的是广度优先搜索,用一个队列来维护,当然也可以用深度优先搜索,但是如果使用递归,会发现LeetCode过不了,这是因为在图形中通常图片(或者说这里的矩阵)一般会很大,递归很容易导致栈溢出,所以即使要用深度优先搜索,也最好使用非递归的实现方式哈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值