LeetCode 130
来源:8-7 floodfill算法,一类经典问题 Number of Islands-
慕妹2978617
2023-08-11
- 被围绕的区域
给你一个 m x n 的矩阵 board ,由若干字符 ‘X’ 和 ‘O’ ,找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
输入:board = [[“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’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
package com.ggxiaozhi.leetcodenew.class8;
import java.util.Arrays;
/**
* 130. 被围绕的区域
* 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
* <p>
* 思路
* 1 floodFill 找到0 然后记录0的合法区域
* 2 找到0但不合法直接返回 不记录
*/
public class Solution130 {
static int[][] way = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
static int m, n;
public static void solve(char[][] board) {
m = board.length;
n = board[0].length;
boolean[][] used = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!used[i][j] && board[i][j] == '0') {
searchZero(board, i, j, used);
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (used[i][j]) {
board[i][j] = 'X';
}
}
}
}
//找到0 后就要判断 4个方向上有没有不合法的 存在 则当前这个0是无效的 不加入used
private static void searchZero(char[][] board, int x, int y, boolean[][] used) {
used[x][y] = true;
for (int[] ints : way) {
int nextX = x + ints[0];
int nextY = y + ints[1];
if (isValid(nextX, nextY)) {
if (!used[nextX][nextY] && board[nextX][nextY] == '0')
searchZero(board, nextX, nextY, used);
} else {
used[x][y] = false;
break;
}
}
}
public static boolean isValid(int x, int y) {
return x >= 0 && y >= 0 && x < m && y < n;
}
public static void main(String[] args) {
char[][] chars = {
{'X', 'X', 'X', 'X'},
{'X', '0', '0', 'X'},
{'X', 'X', '0', 'X'},
{'X', '0', 'X', 'X'}
};
solve(chars);
System.out.println(Arrays.deepToString(chars));
}
}
我这个代码 用官方上述例子跑出来在本地是对的,放到leetcode上就是错的,老师可以帮看下原因吗?
写回答
2回答
-
慕妹2978617
提问者
2023-08-11
本来从搜索O的角度出发,写出
searchZero
不对后,想到排除边缘干扰因此想出
searchEdge
后来看别人的题解,突然恍然大悟,我都写出searchEdge()了, 那isEdgeUsed,不就是标记着哪写O是不用修改的,那剩下的不就全都是'X'了,完全可以不用这个方法。 只需要去掉searchZero()方法 将下面的代码 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!isEdgeUsed[i][j]) { board[i][j] = 'X'; } } } 改成 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!isEdgeUsed[i][j]) { board[i][j] = 'X'; } } } 这个遍历也可以完全不用了 public class Solution { static int[][] way = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; static int m, n; static boolean[][] isEdgeUsed; public static void solve(char[][] board) { m = board.length; n = board[0].length; //合法是否被用过 isEdgeUsed = new boolean[m][n]; //先找到所有边缘 和与边缘连接的O 并记录在 isEdgeUsed中 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!isEdgeUsed[i][j] && board[i][j] == 'O' && isEdge(i, j)) { searchEdge(board, i, j, isEdgeUsed); } } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!isEdgeUsed[i][j]) { board[i][j] = 'X'; } } } } //找到0 后就要判断 4个方向上有没有不合法的 存在 则当前这个0是无效的 不加入used private static void searchEdge(char[][] board, int x, int y, boolean[][] isEdgeUsed) { isEdgeUsed[x][y] = true; for (int[] ints : way) { int nextX = x + ints[0]; int nextY = y + ints[1]; if (isValid(nextX, nextY)) { if (!isEdgeUsed[nextX][nextY] && board[nextX][nextY] == 'O') searchEdge(board, nextX, nextY, isEdgeUsed); } } } public static boolean isValid(int x, int y) { return x >= 0 && y >= 0 && x < m && y < n; } public static boolean isEdge(int x, int y) { return x == 0 || y == 0 || x == m - 1 || y == n - 1; } }
我真是太笨了。不过时间效率还是没到50%(43%)。老师觉得能这个代码还能优化嘛!
012023-08-14 -
慕妹2978617
提问者
2023-08-11
找到原因了,题目是O,我看成了0了。
但是还是有问题,属于是我理解的问题,我以为和边缘连接的O是合法的,需要改成X,但实际不用。我服用下代码想到个方案,但就是感觉有些重复,不知道怎么拆分简化。但是对我来说却比较好理解。老师有时间的话,可以针对我的代码给个优化建议
// char[][] chars = { // {'O', 'O', 'O'}, // {'O', 'O', 'O'}, // {'O', 'O', 'O'}, // }; 我以为 中间的O需要改成X ,所以上面的代码不对 改成了下面的就对了
package com.ggxiaozhi.leetcodenew.class8; import java.util.Arrays; /** * 130. 被围绕的区域 * 给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。 * <p> * 思路 * 1 floodFill 找到0 然后记录0的合法区域 * 2 找到0但不合法直接返回 不记录 */ public class Solution130 { static int[][] way = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; static int m, n; static boolean[][] used; static boolean[][] isEdgeUsed; public static void solve(char[][] board) { m = board.length; n = board[0].length; //合法是否被用过 used = new boolean[m][n]; isEdgeUsed = new boolean[m][n]; //先找到所有边缘 和与边缘连接的O 并记录在 isEdgeUsed中 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (isEdge(i, j)&&!isEdgeUsed[i][j] && board[i][j] == 'O' ) { searchEdge(board, i, j, isEdgeUsed); } } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!isEdge(i, j) && !used[i][j] && board[i][j] == 'O' && !isEdgeUsed[i][i]) { searchZero(board, i, j, used); } } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (used[i][j]) { board[i][j] = 'X'; } } } } //找到0 后就要判断 4个方向上有没有不合法的 存在 则当前这个0是无效的 不加入used private static void searchEdge(char[][] board, int x, int y, boolean[][] isEdgeUsed) { isEdgeUsed[x][y] = true; for (int[] ints : way) { int nextX = x + ints[0]; int nextY = y + ints[1]; if (isValid(nextX, nextY)) { if (!isEdgeUsed[nextX][nextY] && board[nextX][nextY] == 'O') searchEdge(board, nextX, nextY, isEdgeUsed); } } } private static void searchZero(char[][] board, int x, int y, boolean[][] used) { used[x][y] = true; for (int[] ints : way) { int nextX = x + ints[0]; int nextY = y + ints[1]; if (isValid(nextX, nextY) && !isEdgeUsed[nextX][nextY]) { if (!used[nextX][nextY] && board[nextX][nextY] == 'O') searchZero(board, nextX, nextY, used); } else { used[x][y] = false; break; } } } public static boolean isValid(int x, int y) { return x >= 0 && y >= 0 && x < m && y < n; } public static boolean isEdge(int x, int y) { return x == 0 || y == 0 || x == m - 1 || y == n - 1; } public static void main(String[] args) { char[][] chars = { {'X', 'X', 'X', 'X'}, {'X', 'O', 'O', 'X'}, {'X', 'X', 'O', 'X'}, {'X', 'O', 'X', 'X'} }; // char[][] chars = { // {'O', 'O', 'O'}, // {'O', 'O', 'O'}, // {'O', 'O', 'O'}, // }; solve(chars); System.out.println(Arrays.deepToString(chars)); } }
012023-08-11
相似问题