題目鏈接
130. 被圍繞的區域
題目描述
給定一個二維的矩陣,包含 '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'。如果兩個元素在水平或垂直方向相鄰,則稱它們是“相連”的。
解題思路
(1) DFS思路一
利用dfs遞歸將board地圖中所有的“O”的找出,並用兩個數組記錄他們的座標,其次從兩個座標數組中判斷是否包含了邊界點的“O”,如果有則清空數據,如果沒有則直接把兩個座標數組中對應的點改爲“X”即可。
(2) DFS思路二
可以直接從邊界點"O"出發,利用DFS查找所有與邊界點“O”相鄰的“O”,這些點不能改變,其餘“O”直接變爲“X”即可。
AC代碼
(1)DFS實現方式一
class Solution {
// lsX與lxY兩個數組用於"O"的橫縱座標
ArrayList<Integer> lsX = new ArrayList<>();
ArrayList<Integer> lsY = new ArrayList<>();
//dir方向數組(上下左右)
int dir[][] = {{0,1},{1,0},{-1,0},{0,-1}};
void dfs(int x,int y,char[][] map,int[][] view){
//情況一:下標越界
if(x<0 || x>=map.length || y<0 || y>=map[0].length) return;
//情況二:我們尋找的是”O”點,不是“X”點。
if(map[x][y] == 'X') return;
//情況三:該座標點已經遍歷過
if(view[x][y] == 1) return;
if(map[x][y] == 'O'){
//如果座標點對應的字符是我們需要的“O”,則記錄其橫縱座標。並標記此點已經遍歷,防止重複遍歷。
view[x][y] = 1;
lsX.add(x);
lsY.add(y);
}
//DFS框架
for(int i = 0; i < 4; i++){
int xx = x + dir[i][0];
int yy = y + dir[i][1];
dfs(xx,yy,map,view);
}
}
//cal函數用於判斷lsX以及lsY數組中是否包含處於邊界的“O”
int cal(ArrayList<Integer> lsX,ArrayList<Integer> lsY,int a,int b){
if(lsX.contains(new Integer(0)) || lsX.contains(new Integer(a))
|| lsY.contains(new Integer(0)) || lsY.contains(new Integer(b))){
return 1;
}
else return 0;
}
public void solve(char[][] board) {
if(board.length == 0 ) return;
//view數組用於記錄點x,y是否已經遍歷過,防止重複遍歷。
int[][] view = new int[board.length][board[0].length];
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++)
{
if(board[i][j] == 'O'){
dfs(i,j,board,view);
//cal函數用於判斷lsX以及lsY數組中是否包含處於邊界的“O”,如果有,這些點按照題目要求
//不能夠更改,所以清空數組
if(cal(lsX,lsY,board.length-1,board[0].length-1) == 1){
lsY.clear();
lsX.clear();
}
else{
for(int z = 0; z < lsX.size(); z++){
board[lsX.get(z).intValue()][lsY.get(z).intValue()] = 'X';
}
}
}
}
}
}
}
(2)DFS實現方式二
class Solution {
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 從邊緣o開始搜索
boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
if (isEdge && board[i][j] == 'O') {
dfs(board, i, j);
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') {
board[i][j] = 'X';
}
if (board[i][j] == '#') {
board[i][j] = 'O';
}
}
}
}
public void dfs(char[][] board, int i, int j) {
if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == 'X' || board[i][j] == '#') {
// board[i][j] == '#' 說明已經搜索過了.
return;
}
board[i][j] = '#';
dfs(board, i - 1, j); // 上
dfs(board, i + 1, j); // 下
dfs(board, i, j - 1); // 左
dfs(board, i, j + 1); // 右
}
}
鏈接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/
(3)DFS非遞歸實現
非遞歸的方式,我們需要記錄每一次遍歷過的位置,我們用 stack 來記錄,因爲它先進後出的特點。而位置我們定義一個內部類 Pos 來標記橫座標和縱座標。注意的是,在寫非遞歸的時候,我們每次查看 stack 頂,但是並不出 stack,直到這個位置上下左右都搜索不到的時候出棧。(代碼中continue語句是關鍵)
class Solution {
public class Pos{
int i;
int j;
Pos(int i, int j) {
this.i = i;
this.j = j;
}
}
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 從邊緣第一個是o的開始搜索
boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
if (isEdge && board[i][j] == 'O') {
dfs(board, i, j);
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') {
board[i][j] = 'X';
}
if (board[i][j] == '#') {
board[i][j] = 'O';
}
}
}
}
public void dfs(char[][] board, int i, int j) {
Stack<Pos> stack = new Stack<>();
stack.push(new Pos(i, j));
board[i][j] = '#';
while (!stack.isEmpty()) {
// 取出當前stack 頂, 不彈出.
Pos current = stack.peek();
// 上
if (current.i - 1 >= 0
&& board[current.i - 1][current.j] == 'O') {
stack.push(new Pos(current.i - 1, current.j));
board[current.i - 1][current.j] = '#';
continue;//continue語句是關鍵
}
// 下
if (current.i + 1 <= board.length - 1
&& board[current.i + 1][current.j] == 'O') {
stack.push(new Pos(current.i + 1, current.j));
board[current.i + 1][current.j] = '#';
continue;
}
// 左
if (current.j - 1 >= 0
&& board[current.i][current.j - 1] == 'O') {
stack.push(new Pos(current.i, current.j - 1));
board[current.i][current.j - 1] = '#';
continue;
}
// 右
if (current.j + 1 <= board[0].length - 1
&& board[current.i][current.j + 1] == 'O') {
stack.push(new Pos(current.i, current.j + 1));
board[current.i][current.j + 1] = '#';
continue;
}
// 如果上下左右都搜索不到,本次搜索結束,彈出stack
stack.pop();
}
}
}
作者:Ac_pipe
鏈接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/
(4)BFS實現
dfs 非遞歸的時候我們用 stack 來記錄狀態,而 bfs 非遞歸,我們則用隊列來記錄狀態。和 dfs 不同的是,dfs 中搜索上下左右,只要搜索到一個滿足條件,我們就順着該方向繼續搜索,所以你可以看到 dfs 代碼中,只要滿足條件,就入 Stack,然後 continue 本次搜索,進行下一次搜索,直到搜索到沒有滿足條件的時候出 stack。而 dfs 中,我們要把上下左右滿足條件的都入隊,所以搜索的時候就不能 continue。大家可以對比下兩者的代碼,體會 bfs 和 dfs 的差異。
class Solution {
public class Pos{
int i;
int j;
Pos(int i, int j) {
this.i = i;
this.j = j;
}
}
public void solve(char[][] board) {
if (board == null || board.length == 0) return;
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 從邊緣第一個是o的開始搜索
boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
if (isEdge && board[i][j] == 'O') {
bfs(board, i, j);
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') {
board[i][j] = 'X';
}
if (board[i][j] == '#') {
board[i][j] = 'O';
}
}
}
}
public void bfs(char[][] board, int i, int j) {
Queue<Pos> queue = new LinkedList<>();
queue.add(new Pos(i, j));
board[i][j] = '#';
while (!queue.isEmpty()) {
Pos current = queue.poll();
// 上
if (current.i - 1 >= 0
&& board[current.i - 1][current.j] == 'O') {
queue.add(new Pos(current.i - 1, current.j));
board[current.i - 1][current.j] = '#';
// 沒有continue.
}
// 下
if (current.i + 1 <= board.length - 1
&& board[current.i + 1][current.j] == 'O') {
queue.add(new Pos(current.i + 1, current.j));
board[current.i + 1][current.j] = '#';
}
// 左
if (current.j - 1 >= 0
&& board[current.i][current.j - 1] == 'O') {
queue.add(new Pos(current.i, current.j - 1));
board[current.i][current.j - 1] = '#';
}
// 右
if (current.j + 1 <= board[0].length - 1
&& board[current.i][current.j + 1] == 'O') {
queue.add(new Pos(current.i, current.j + 1));
board[current.i][current.j + 1] = '#';
}
}
}
}
作者:Ac_pipe
鏈接:https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/