Question
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
本题难度Medium。有2种算法分别是: DFS和BFS。(实际上2个算法本质上是一样的,我只写DFS)
DFS
【复杂度】
时间 O(MN) 空间 O(MN)
【思路】
从矩阵的四条边上的点作为起点,搜索连续的一块区域上值为'O'
的点并改为'+'
(进行标记)。这里我们用BFS或DFS进行搜索。对四条边上所有点都进行过这个步骤后,矩阵内剩余的'O'
就是被包围的'O'
。此时再对所有点遍历一遍,将'+'
改回为'O'
,而剩余的'O'
变为'X'
。
Tricky
这道题目的通过率很低(17.3%),问题不在于这题目有多难,而在于该测试系统(Leetcode)对于函数调用栈深度的限制比较严格,而对于数据空间的限制却不严格。相信大多数同僚在开始都会想到以下的代码(这也是我的想法):
public class Solution {
public void solve(char[][] board) {
//require
int m=board.length;
if(m<1)return;
int n=board[0].length;
//invariant
for(int i=0;i<n;i++){
dfs(board,0,i);
dfs(board,m-1,i);
}
for(int i=0;i<m;i++){
dfs(board,i,0);
dfs(board,i,n-1);
}
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(board[i][j]=='O')
board[i][j]='X';
else if(board[i][j]=='+')
board[i][j]='O';
}
}
//问题就出在这里面,DFS是函数调用实现的
private void dfs(char[][] board,int i,int j){
//require
int m=board.length;
int n=board[0].length;
//base case
if(i<0||i>m-1||j<0||j>n-1)return;
if(board[i][j]=='O'){
board[i][j]='+';
dfs(board,i-1,j);
dfs(board,i,j-1);
dfs(board,i+1,j);
dfs(board,i,j+1);
}
}
}
上面的代码并没有错,只是系统限制了调用栈深度导致Stackoverflow。要想规避该限制得到AC,就得用数据栈:
public class Solution {
public void solve(char[][] board) {
//require
int m=board.length;
if(m<1)return;
int n=board[0].length;
//invariant
for(int i=0;i<n;i++){
if(board[0][i]=='O')
dfs(board,0,i);
if(board[m-1][i]=='O')
dfs(board,m-1,i);
}
for(int i=0;i<m;i++){
if(board[i][0]=='O')
dfs(board,i,0);
if(board[i][n-1]=='O')
dfs(board,i,n-1);
}
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(board[i][j]=='O')
board[i][j]='X';
else if(board[i][j]=='+')
board[i][j]='O';
}
}
class Pair{
public int x;
public int y;
Pair(int x,int y){
this.x=x;
this.y=y;
}
}
//实际上都是一样的,换汤不换药
private void dfs(char[][] board,int i,int j){
//require
int m=board.length;
int n=board[0].length;
int[] dirX = {-1,0,1,0};
int[] dirY = {0,1,0,-1};
Stack<Pair> stack=new Stack<>();
stack.push(new Pair(i,j));
while(!stack.isEmpty()){
Pair pair=stack.pop();
board[pair.x][pair.y]='+';
for(int k=0;k<dirX.length;k++){
int x=pair.x+dirX[k];
int y=pair.y+dirY[k];
if(0<=x&&x<m&&0<=y&&y<n&&board[x][y]=='O')
stack.push(new Pair(x,y));
}
}
}
}