问题:
难度:medium
说明:
题目会输入一个二维char[][] charArr,如果发现有X包围O地区,就将O的上下左右联通块(四个斜角的不属于联通块)全部变成X,如果O在边界,就视为没有包围,有点像翻转棋。
问题链接:https://leetcode.com/problems/surrounded-regions/
输入案例:
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:
// 中间几个O被包围就改成X,然而边界的O视为没有被包围,所以不用修改
X X X X
X X X X
X X X X
X O X X
我的代码:
用bfs + visited处理,这个做法跟岛屿扫描很相似,所以可以根据那个处理处来,相对来说算法效率略慢,7ms,也没有特别短和容易的代码,大多业务处理所以就没看其他代码了。
public class SurroundedRegions {
public static void main(String[] args) {
Solution solution = new SurroundedRegions().new Solution();
char[][] board01 = {{'X'}};
// 边界元素不进行遍历,并且触边情况要跳出联通块计算
char[][] board02 = {
{'X','O','X','X'},
{'O','X','O','X'},
{'X','O','X','O'},
{'O','X','O','X'}};
// visited已经是1的就不要遍历
char[][] board03 = {
{'O','X','X','O','X'},
{'X','O','O','X','O'},
{'X','O','X','O','X'},
{'O','X','O','O','O'},
{'X','X','O','X','O'}};
// 7,6那个地方,因为判断里面一旦触边就跳出,导致四周被遍历为1,只有他自己是0就出错了
// 改成flag判断是否触边,然后遍历所有联通块即可
char[][] board04 = {
{'O','X','O','O','O','O','O','O','O'},
{'O','O','O','X','O','O','O','O','X'},
{'O','X','O','X','O','O','O','O','X'},
{'O','O','O','O','X','O','O','O','O'},
{'X','O','O','O','O','O','O','O','X'},
{'X','X','O','O','X','O','X','O','X'},
{'O','O','O','X','O','O','O','O','O'},
{'O','O','O','X','O','O','O','O','O'},
{'O','O','O','O','O','X','X','O','O'}};
// 末尾判断出错
solution.solve(board01);
solution.solve(board02);
solution.solve(board03);
solution.solve(board04);
printf(board01);
printf(board02);
printf(board03);
printf(board04);
}
private static void printf(char[][] board01) {
for(int i = 0;i < board01.length;i ++) {
for(int j = 0;j < board01[0].length;j ++) {
System.out.print(board01[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
class Solution {
public void solve(char[][] board) {
// 长宽3以下的都不会被包围
if(board == null || board.length < 3 || board[0].length < 3) return;
// 分别拿出二维数组的xy以及 - 1的数
int x = board.length;
int y = board[0].length;
int xd = x - 1;
int yd = y - 1;
char O = 'O';
// 访问表
int[][] visited = new int[x][y];
// 用于统计陆地的队列
int[][] lands = new int[x * y][2];
// i j 从 1 开始都不遍历边界的
for(int i = 1;i < xd;i ++) {
for(int j = 1;j < yd;j ++) {
if(visited[i][j] != 1) {
// 队列头尾指针
// land begin
int lbegin = -1;
// land end
int lend = 0;
visited[i][j] = 1;
// 非边界元素遍历
if(board[i][j] == O)
{
lands[++ lbegin][0] = i;
lands[lbegin][1] = j;
boolean flag = true;
while(lend - lbegin >= 0)
{
int x1 = lands[lbegin][0];
int y1 = lands[lbegin ++][1];
// 触边警告,因为board04原因,所以触边依然要继续遍历
if(x1 == xd
|| x1 == 0
|| y1 == yd
|| y1 == 0)
{
flag = false;
}
// 添加不越边约束
if(x1 + 1 < x && board[x1 + 1][y1] == O && visited[x1 + 1][y1] != 1) {
lands[++ lend][0] = x1 + 1;
lands[lend][1] = y1;
visited[x1 + 1][y1] = 1;
}
// 只添加元素为 O 的
if(x1 - 1 >= 0 && board[x1 - 1][y1] == O && visited[x1 - 1][y1] != 1) {
lands[++ lend][0] = x1 - 1;
lands[lend][1] = y1;
visited[x1 - 1][y1] = 1;
}
if(y1 + 1 < y && board[x1][y1 + 1] == O && visited[x1][y1 + 1] != 1) {
lands[++ lend][0] = x1;
lands[lend][1] = y1 + 1;
visited[x1][y1 + 1] = 1;
}
if(y1 - 1 >= 0 && board[x1][y1 - 1] == O && visited[x1][y1 - 1] != 1) {
lands[++ lend][0] = x1;
lands[lend][1] = y1 - 1;
visited[x1][y1 - 1] = 1;
}
}
// 如果已经是触边的联通块就不覆盖
if(flag) {
// 进行覆盖
while(lend >= 0) {
int[] site2 = lands[lend --];
board[site2[0]][site2[1]] = 'X';
}
}
}
}
}
}
return;
}
}
}