1. 问题描述:
给定一个二维的矩阵,包含 'X'
和 'O'
(字母 O)。
找到所有被 'X'
围绕的区域,并将这些区域里所有的 'O'
用 'X'
填充。
示例:
X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O'
都不会被填充为 'X'
。 任何不在边界上,或不与边界上的 'O'
相连的 'O'
最终都会被填充为 'X'
。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的
2. 思路分析:
① 首先对于这样的题目我们是可以使用dfs的,因为dfs可以搜索所有的路径,并且可以进行联通性的检测(将会遍历以当前位置联通的区域)并且我们可以知道需要求解的是被X完全包围的所有O,所以我们可以从边界上的O的位置出发,开始dfs,所有经过dfs调用的地方都是与边界进行联通的,我们可以对dfs遍历的地方进行标记,这样我们才可以在遍历之后找到所有与边界上联通的区域,而这些区域正是没有被X完全包围的,可以使用其余的符号进行标记比如*这些符号,等到所有边界上的O经过dfs之后会将所有联通的区域进行标记,最后我们再将另外没有标记的地方全部置为X
② 除了使用dfs深度优先搜索之外还可以使用bfs宽度优先搜索,道理也是类似的,只是bfs搜索的方法与dfs不太一样,dfs是先纵后横,而bfs是沿着周围的四个方向进行扩展,但是实现的思路是一样的
③ 因为这个问题其实是连通性的检测性问题,所以我们还可以使用并查集来解决,使用一个节点来作为边界上的节点以及边界上与其余区域联通部分父节点,这样所有在边界上的点以及与内部相连通的点都会被加入到根节点中,这样在最后遍历数组的时候将所有在这个父节点上的字符O保持不变,其余的变为X,但是在测试的时候有一小部分的数据还是没有通过,不知道是啥原因
后面的话只是为了练习一下并查集的方法,模拟方法一的思路将使用并查集将所有边界上与内部的区域连接在一个父节点,之后使用dfs将其这些区域置为其余的字符,等到最后的时候遍历数组将这些标记的位置还原为O其余的变为X,所以与dfs的思路没有什么区别只是为了练习一下dfs,耗时还比dfs大,因为这里多了一个并查集的操作(感觉没有什么用)
3. 代码如下:
dfs代码如下:
import java.util.Scanner;
public class Solution {
static int pos[][] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public static void solve(char[][] board) {
if (board == null || board.length == 0) return;
int r = board.length;
int c = board[0].length;
/*这个需要提前判断一下假如只有一行那么直接return因为在执行下一句代码的时候回出现数组越界的问题*/
for (int i = 0; i < r; ++i){
for (int j = 0; j < c; ++j){
if ((i == 0 || j == 0 || i == r - 1 || j == c - 1) && board[i][j] == 'O'){
dfs(i, j, board);
}
}
}
/*将之前dfs搜索边界的O标记的地方填充为O, 将内部包围的地方使用X进行填充*/
for (int i = 0; i < r; ++i){
for (int j = 0; j < c; ++j){
if (board[i][j] == 'X') continue;
else if (board[i][j] == 'O') board[i][j] = 'X';
/*最后这个是搜索之后填充为*的部分恢复为O*/
else board[i][j] = 'O';
}
}
}
private static void dfs(int r, int c, char[][] board) {
/*r: 起点, c: 终点, 将边界中与内部联通的地方全部变为*占位符号表示这个地方是不能够被填充的*/
board[r][c] = '*';
/*四个方向对应着的四个平行状态*/
for (int i = 0; i < 4; ++i){
int x = r + pos[i][0];
int y = c + pos[i][1];
/*先判断再决定是否可以递归下去
* 寻找边界与内部区域相通的部分, 我这里是先判断再决定是否执行下去
* */
if (x >= 0 && x < board.length && y >= 0 && y < board[0].length && board[x][y] == 'O'){
dfs(x, y, board);
}
}
}
}
并查集代码如下:
import java.util.Scanner;
public class Solution {
/*采用并查集与dfs结合的方法来解决*/
public static class UnionFindNode{
int parents[];
public UnionFindNode(int total) {
parents = new int[total];
for (int i = 0; i < total; ++i){
parents[i] = i;
}
}
public int find(int node){
if (parents[node] == node) return node;
int parent = find(parents[node]);
parents[node] = parent;
return parent;
}
public void union(int first, int second){
int firstParent = find(first);
int secondParent = find(second);
if (firstParent != secondParent){
parents[secondParent] = firstParent;
}
}
}
public static void solve(char[][] board) {
if (board == null || board.length == 0) return;
int r = board.length;
int c = board[0].length;
int node = r * c;
UnionFindNode unionFindNode = new UnionFindNode(r * c + 1);
for (int i = 0; i < r; ++i){
for (int j = 0; j <c; ++j){
if (board[i][j] == 'O'){
if (i - 1 >= 0 && board[i - 1][j] == 'O'){
unionFindNode.union(i * c + j, (i - 1) * c + j);
}
if (i + 1 < r && board[i + 1][j] == 'O'){
unionFindNode.union(i * c + j, (i + 1) * c + j);
}
if (j - 1 >= 0 && board[i][j - 1] == 'O'){
unionFindNode.union(i * c + j, i * c + j - 1);
}
if (j + 1 < c && board[i][j + 1] == 'O'){
unionFindNode.union(i * c + j, i * c + j + 1);
}
}
}
}
/*for (int i = 0; i < r * c; ++i){
if (i % c == 0) System.out.println();
System.out.print(unionFindNode.parents[i] + " ");
}
System.out.println();*/
/*for (int i = 0; i < r; ++i){
for (int j = 0; j < c; ++j){
System.out.print(unionFindNode.find(i * c + j) + " ");
}
System.out.println();
}*/
/*dfs进行连通性检测*/
for (int i = 0; i < r; ++i){
for (int j = 0; j < c; ++j){
if (i == 0 || i == r - 1 || j == 0 || j == c - 1){
if (board[i][j] == 'O'){
dfs(unionFindNode, board, i, j);
}
}
}
}
for (int i = 0; i < r; ++i){
for (int j = 0; j < c; ++j){
if (board[i][j] == '*') board[i][j] = 'O';
else board[i][j] = 'X';
}
}
}
private static void dfs(UnionFindNode unionFindNode , char board[][], int x, int y) {
board[x][y] = '*';
int r = board.length;
int c = board[0].length;
if (x - 1 >= 0 && board[x - 1][y] == 'O' && unionFindNode.find(x * c + y) == unionFindNode.find((x - 1) * c + y)){
dfs(unionFindNode, board, x - 1, y);
}
if (x + 1 < r && board[x + 1][y] == 'O' && unionFindNode.find(x * c + y) == unionFindNode.find((x + 1) * c + y)){
dfs(unionFindNode, board, x + 1, y);
}
if (y - 1 >= 0 && board[x][y - 1] == 'O' && unionFindNode.find(x * c + y) == unionFindNode.find(x * c + y - 1)){
dfs(unionFindNode, board, x, y - 1);
}
if (y + 1 < c && board[x][y + 1] == 'O' && unionFindNode.find(x * c + y) == unionFindNode.find(x * c + y + 1)){
dfs(unionFindNode, board, x, y + 1);
}
}
private static boolean isConnected(UnionFindNode unionFindNode, int node, int cur) {
return unionFindNode.find(node) == unionFindNode.find(cur);
}
}