【LeetCode】130. 被圍繞的區域

題目鏈接

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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章