这是一道Acceptance不到20%的Medium题。通常这种情况就是有需要细心考虑的边界条件或者递归终止条件。
这题思路的话很容易想,从外围找O,找到了就用DFS或者BFS之类的把都是O的neighbor赋值成Y。然后扫两遍,把O变成X,Y变回O。
主要看看DFS部分吧,比较典型的floodfill。注意终止条件写法。
另外网上有很多用用QUEUE实现了BFS,也该写写的,今天太jb累了,真的,在公司写了一天胶水代码,困的一B。睡觉了。
public class Solution {
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int row = board.length;
int col = board[0].length;
for (int i = 0; i < row; i++) {
dfs(board, i, 0, row, col);
if (col > 1)
//这样的话只有一列的情况不用单独处理了
dfs(board, i, col - 1, row, col);
}
//这里可以掐头去尾
for (int i = 1; i < col - 1; i++) {
dfs(board, 0, i, row, col);
if (row > 1)
dfs(board, row - 1, i , row, col);
}
for (int i = 0; i < row; i++)
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] == 'Y') {
board[i][j] = 'O';
}
}
}
private void dfs(char[][] board, int i, int j, int row, int col) {
if (board[i][j] == 'O') {
board[i][j] = 'Y';
// if (i < 0 || i > row - 1 || j < 0 || j > col - 1) return;
if (i - 1 > 0) dfs(board, i - 1, j, row, col);
if (i + 1 < row) dfs(board, i + 1, j, row, col);
if (j - 1 > 0) dfs(board, i, j - 1, row, col);
if (j + 1 < col) dfs(board, i, j + 1, row, col);
}
}
}
DFS,BFS可以多搜几种解法看看,比如下面的ref里的几种;但是我看了很多种解法,只有上面贴的这种在检查下一次dfs是否满足的写法才勉强AC(估计速度也是很慢),其他的都会stackOverFlow,我一开始觉得是哪里有逻辑问题,因为不AC的话一般是TLE啊,这题为什么是SOF呢。。。看了http://blog.csdn.net/ChilseaSai/article/details/50375111 之后明白了,就是典型的递归层数过深产生的啊。。每一次递归都是一个栈,Leetcode给出了一些非常屌的testcase,长达几KB的矩阵。。我也是醉了:
所以,同样是DFS,在下一次运行开始之前检查,和利用终止条件检查,前者效率会高于后者(前者从本层就阻止了进入下一层DFS,后者是进入下一层DFS再return)。另外,对于数据量大的testcase,用BFS。
那如果不考虑那么大的test case,这题的dfs部分还可以这么写:
private void dfs(char[][] board, int x, int y, int row, int col) {
if (x >= 0 && x < row && y >=0 && y
或者这么写:
private void dfs(char[][] board, int i, int j, int row, int col) {
if (i < 0 || i >= row || j < 0 || j >= col || board[i][j] != 'O') return;
board[i][j] = 'Y';
dfs(board, i - 1, j, row, col);
dfs(board, i + 1, j, row, col);
dfs(board, i, j - 1, row, col);
dfs(board, i, j + 1, row, col);
}
总之,能终止递归就可以了。
用BFS的话可以这么写:
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int row = board.length;
int col = board[0].length;
for (int i = 0; i < row; i++) {
if (board[i][0] == 'O')
bfs(board, i, 0, row, col);
if (col > 1)
if (board[i][col-1] == 'O')
//这样的话只有一列的情况不用单独处理了
bfs(board, i, col - 1, row, col);
}
//这里可以掐头去尾
for (int i = 1; i < col - 1; i++) {
if (board[0][i] == 'O')
bfs(board, 0, i, row, col);
if (row > 1)
if (board[row-1][i] == 'O')
bfs(board, row - 1, i, row, col);
}
for (int i = 0; i < row; i++)
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] == 'Y') {
board[i][j] = 'O';
}
}
}
private void bfs(char[][] board, int i, int j, int row, int col) {
//泛型只能有一个参数,所以这里用了Pair保存坐标(也可用余数和商来解析,可参考http://blog.csdn.net/ChilseaSai/article/details/50375111)
LinkedList queue = new LinkedList<>();
Pair pair = new Pair(i, j);
queue.add(pair);
while (!queue.isEmpty()) {
Pair p = queue.poll();
int x = p.x;
int y = p.y;
//因为floodfill向四个方向扩散,所以可能回到刚才蔓延过的地方;如果不加这句,提交的时候会TLE
if (board[x][y] == 'Y') continue;
if (board[x][y] == 'O') {
board[x][y] = 'Y';
}
if (x - 1 >= 0 && board[x - 1][y] == 'O') {
queue.add(new Pair(x - 1, y));
}
if (x + 1 < row && board[x + 1][y] == 'O') {
queue.add(new Pair(x + 1, y));
}
if (y - 1 >= 0 && board[x][y - 1] == 'O') {
queue.add(new Pair(x, y - 1));
}
if (y + 1 < col && board[x][y + 1] == 'O') {
queue.add(new Pair(x, y + 1));
}
}
}
class Pair {
int x;
int y;
Pair(int x, int y) {
this.x = x;
this.y = y;
}
}
再稍微提一下,遍历四个边的方法还可以这么写:
//对所有在边上的O节点进行BFS
for(int i=0;i
参考的是这里,复杂度是一样的都是O(m*n)。
另外,本题还可以用并查集来实现,leetcode的discussion里有。
http://blog.sina.com.cn/s/blog_b9285de20101j1dt.html
http://www.cnblogs.com/guyufei/p/3448824.html
http://blog.csdn.net/ChilseaSai/article/details/50375111