130. Surrounded Regions

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
For 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:

X X X X
X X X X
X X X X
X O X X

Solution1:邊界DFS (Recursive)

(遞歸可能存在 stack overflow)
思路:找邊界聯(lián)通的所有的0,置為*。然后0置為X,*置為0
a最好在遞歸前就check是否visited或出界赃阀,如果沒有呐赡,再遞歸去visit
b或是寫法簡單的:直接dfs跨算,但每次進(jìn)入遞歸再檢查是否visited/出界
Time Complexity: O(mn) Space Complexity: O(mn)

Solution1.2:邊界DFS (Recursive) Round1

Time Complexity: O(mn) Space Complexity: O(mn)

Solution2:邊界DFS (stack)

思路:找聯(lián)通的所有的0,置為*舌缤。然后0置為X瓣距,*置為1
在放入stack前就check是否visited黔帕,如果沒有visit過,再放入stack
Time Complexity: O(mn) Space Complexity: O(mn)

Solution3:邊界BFS (queue)

思路:找聯(lián)通的所有的0蹈丸,置為*成黄。然后0置為X,*置為1
在放入queue前就check是否visited逻杖,如果沒有visit過慨默,再放入queue
Time Complexity: O(mn) Space Complexity: O(mn)

Solution4:Union Find

思路:每個位置的元素初始都assigned 一個id,并多建一個id[mn]作為邊緣標(biāo)志弧腥。遍歷將所有的0,若其是邊緣元素的話潮太,將其和"邊緣"id(id[mn]) union管搪,如果是中間元素虾攻,將其和周圍四鄰域的union。最終沒有和邊緣connected的置為'X'
Time Complexity: O(NlogN)? Space Complexity: O(N) N=m*n

Solution1a Code:

class Solution {
    public void solve(char[][] board) {
        if (board.length == 0 || board[0].length == 0)
            return;
        if (board.length < 2 || board[0].length < 2)
            return;
        int m = board.length, n = board[0].length;
        //Any 'O' connected to a boundary can't be turned to 'X', so ...
        //Start from first and last column, turn 'O' to '*'.
        for (int i = 0; i < m; i++) {
            if (board[i][0] == 'O')
                boundaryDFS(board, i, 0);
            if (board[i][n-1] == 'O')
                boundaryDFS(board, i, n-1); 
        }
        //Start from first and last row, turn '0' to '*'
        for (int j = 0; j < n; j++) {
            if (board[0][j] == 'O')
                boundaryDFS(board, 0, j);
            if (board[m-1][j] == 'O')
                boundaryDFS(board, m-1, j); 
        }
        //post-prcessing, turn 'O' to 'X', '*' back to 'O', keep 'X' intact.
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
                else if (board[i][j] == '*')
                    board[i][j] = 'O';
            }
        }
    }
    //Use DFS algo to turn internal however boundary-connected 'O' to '*';
    private void boundaryDFS(char[][] board, int i, int j) {
        //if (i < 0 || i > board.length - 1 || j < 0 || j > board[0].length - 1) return;
        board[i][j] = '*';
        if (i > 1 && board[i - 1][j] == 'O')
            boundaryDFS(board, i - 1, j);
        if (i < board.length - 2 && board[i + 1][j] == 'O')
            boundaryDFS(board, i+1, j);
        if (j > 1 && board[i][j - 1] == 'O')
            boundaryDFS(board, i, j - 1);
        if (j < board[i].length - 2 && board[i][j + 1] == 'O' )
            boundaryDFS(board, i, j + 1);
    }
    
}

Solution1b Code:

// overflow in this problem for some reason
//Use DFS algo to turn internal however boundary-connected 'O' to '*';
    private void boundaryDFS(char[][] board, int i, int j) {
        if (i < 0 || i > board.length - 1 || j < 0 || j > board[0].length - 1 || board[i][j] != 'O')
            return;
        board[i][j] = '*';
        boundaryDFS(board, i - 1, j);
        boundaryDFS(board, i + 1, j);
        boundaryDFS(board, i, j - 1);
        boundaryDFS(board, i, j + 1);
    }

Solution1.2 Code:

class Solution {
    public void solve(char[][] board) {
        if(board == null || board.length == 0 || board[0].length == 0) return;
        
        // dfs to find all 'O' that are connected to the edge
        for(int row = 0; row < board.length; row++) {
            if(board[row][0] == 'O') {
                dfs(board, row, 0);
            }
            if(board[row][board[0].length - 1] == 'O') {
                dfs(board, row, board[0].length - 1);
            }
        }
        
        for(int col = 0; col < board[0].length; col++) {
            if(board[0][col] == 'O') {
                dfs(board, 0, col);
            }
            if(board[board.length - 1][col] == 'O') {
                dfs(board, board.length - 1, col);
            } 
        }
        
        // flip
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                if(board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
                else if(board[i][j] == 'E') {
                    board[i][j] = 'O';
                }
            }
        }
    }
    
    private void dfs(char[][] board, int row, int col) {
        board[row][col] = 'E';
        
        if(row > 0 && board[row - 1][col] == 'O') {
            dfs(board, row - 1, col);
        }
        if(row < board.length - 1 && board[row + 1][col] == 'O') {
            dfs(board, row + 1, col);
        }
        if(col > 0 && board[row][col - 1] == 'O') {
            dfs(board, row, col - 1);
        }
        if(col < board[0].length - 1 && board[row][col + 1] == 'O') {
            dfs(board, row, col + 1);
        }
    }
}

Solution2 Code:

class Solution {
    public void solve(char[][] board) {
        if (board.length == 0 || board[0].length == 0)
            return;
        if (board.length < 2 || board[0].length < 2)
            return;
        int m = board.length, n = board[0].length;
        
        Deque<Point> stack = new ArrayDeque<Point>();
        
        //Any 'O' connected to a boundary can't be turned to 'X', so ...
        //Start from first and last column, turn 'O' to '*'.
        for (int i = 0; i < m; i++) {
            if (board[i][0] == 'O') {
                board[i][0] = '*';
                stack.add(new Point(i, 0));
            }
            if (board[i][n - 1] == 'O') {
                board[i][n - 1] = '*';
                stack.add(new Point(i, n - 1));
            }
        }
        //Start from first and last row, turn '0' to '*'
        for (int j = 0; j < n; j++) {
            if (board[0][j] == 'O') {
                board[0][j] = '*';
                stack.push(new Point(0, j));
            }
            if (board[m - 1][j] == 'O') {
                board[m - 1][j] = '*';
                stack.push(new Point(m - 1, j));
            }
        }
        
        //BFS for the 'O's, and mark it as '+'
        while (!stack.isEmpty()){
            Point p = stack.pop();
            int row = p.x;
            int col = p.y;
            if (row - 1 >= 0 && board[row - 1][col] == 'O') {
                board[row - 1][col] = '*'; 
                stack.push(new Point(row - 1, col));
            }
            if (row + 1 < m && board[row + 1][col] == 'O') {
                board[row + 1][col] = '*'; 
                stack.push(new Point(row + 1, col));
            }
            if (col - 1 >= 0 && board[row][col - 1] == 'O') {
                board[row][col - 1] = '*'; 
                stack.push(new Point(row, col - 1));
            }
            if (col + 1 < n && board[row][col + 1] == 'O') {
                board[row][col + 1] = '*'; 
                stack.push(new Point(row, col + 1));
            }                 
        }
        
        //post-prcessing, turn 'O' to 'X', '*' back to 'O', keep 'X' intact.
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
                else if (board[i][j] == '*')
                    board[i][j] = 'O';
            }
        }
    }

    
}

Solution3 Code:

class Solution {
    public void solve(char[][] board) {
        if (board.length == 0 || board[0].length == 0)
            return;
        if (board.length < 2 || board[0].length < 2)
            return;
        int m = board.length, n = board[0].length;
        
        Queue<Point> queue = new LinkedList<Point>();
        
        //Any 'O' connected to a boundary can't be turned to 'X', so ...
        //Start from first and last column, turn 'O' to '*'.
        for (int i = 0; i < m; i++) {
            if (board[i][0] == 'O') {
                board[i][0] = '*';
                queue.add(new Point(i, 0));
            }
            if (board[i][n - 1] == 'O') {
                board[i][n - 1] = '*';
                queue.add(new Point(i, n - 1));
            }
        }
        //Start from first and last row, turn '0' to '*'
        for (int j = 0; j < n; j++) {
            if (board[0][j] == 'O') {
                board[0][j] = '*';
                queue.add(new Point(0, j));
            }
            if (board[m - 1][j] == 'O') {
                board[m - 1][j] = '*';
                queue.add(new Point(m - 1, j));
            }
        }
        
        //BFS for the 'O's, and mark it as '+'
        while (!queue.isEmpty()){
            Point p = queue.poll();
            int row = p.x;
            int col = p.y;
            if (row - 1 >= 0 && board[row - 1][col] == 'O') {
                board[row - 1][col] = '*'; 
                queue.add(new Point(row - 1, col));
            }
            if (row + 1 < m && board[row + 1][col] == 'O') {
                board[row + 1][col] = '*'; 
                queue.add(new Point(row + 1, col));
            }
            if (col - 1 >= 0 && board[row][col - 1] == 'O') {
                board[row][col - 1] = '*'; 
                queue.add(new Point(row, col - 1));
            }
            if (col + 1 < n && board[row][col + 1] == 'O') {
                board[row][col + 1] = '*'; 
                queue.add(new Point(row, col + 1));
            }                 
        }
        
        //post-prcessing, turn 'O' to 'X', '*' back to 'O', keep 'X' intact.
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (board[i][j] == 'O')
                    board[i][j] = 'X';
                else if (board[i][j] == '*')
                    board[i][j] = 'O';
            }
        }
    }
}

Solution4 Code:

class Solution {
    class UF {
        private int[] id;  
        private int[] sz;  // for an id, the number of elements in that id
        private int count;

        public UF(int m, int n) {
            
            int N = m * n + 1;
            this.id = new int[N];
            this.sz = new int[N];
            this.count = 0;
            
            // init
            for (int i = 0; i < N; i++) {
                this.id[i] = i;
                this.sz[i] = 1;
                this.count++;
            }
        }

        public void union(int p, int q) {
            int p_root = find(p), q_root = find(q);
            // weighted quick union
            ///*
            if(p_root == q_root) return;
            if (sz[p_root] < sz[q_root]) { 
                id[p_root] = q_root; sz[q_root] += sz[p_root];
            } else {
                id[q_root] = p_root; sz[p_root] += sz[q_root];
            }
            --count;
            //*/
            
            // regular
            /*
            if(p_root == q_root) return;
            id[p_root] = q_root;
            --count;
            */
        }

        public int find(int i) { // path compression
            for (;i != id[i]; i = id[i])
                id[i] = id[id[i]]; 
            return i;
        }

        public boolean connected(int p, int q) {
            int p_root = find(p);
            int q_root = find(q);
            if(p_root != q_root) return false;
            else return true;
        }

        public int count() { 
            return this.count; 
        }
        
    }
    
    
    
    public void solve(char[][] board) {
        if(board.length == 0 || board[0].length == 0) return;
        
        int m = board.length, n = board[0].length;
        UF uf = new UF(m, n);

        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {

                // if a 'O' node is on the boundry, connect it to the dummy node. no need to new board[m * n + 1]
                if((i == 0 || i == m - 1 || j == 0 || j == n - 1) && board[i][j] == 'O') {
                    uf.union(i * n + j, m * n);
                }
                else if(board[i][j] == 'O') // connect a 'O' node to its neighbour 'O' nodes
                {
                    if(board[i - 1][j] == 'O') {
                        uf.union(i * n + j, (i - 1) * n + j);
                    }
                    if(board[i + 1][j] == 'O') {
                        uf.union(i * n + j, (i + 1) * n + j);
                    }
                    if(board[i][j - 1] == 'O') {
                        uf.union(i * n + j, i * n + j - 1);
                    }
                    if(board[i][j + 1] == 'O') {
                        uf.union(i * n + j, i * n + j + 1);
                    }
                }              
            }
        }
        
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(!uf.connected(i * n + j, m * n)){ // if a 'O' node is not connected to the dummy node, it is captured
                    board[i][j] = 'X';
                }
            }
        }
    }
    
    
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末更鲁,一起剝皮案震驚了整個濱河市霎箍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌澡为,老刑警劉巖漂坏,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異媒至,居然都是意外死亡顶别,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門拒啰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驯绎,“玉大人,你說我怎么就攤上這事谋旦∈JВ” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵册着,是天一觀的道長拴孤。 經(jīng)常有香客問我,道長甲捏,這世上最難降的妖魔是什么演熟? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮摊鸡,結(jié)果婚禮上绽媒,老公的妹妹穿的比我還像新娘。我一直安慰自己免猾,他們只是感情好是辕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著猎提,像睡著了一般获三。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锨苏,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天疙教,我揣著相機(jī)與錄音,去河邊找鬼伞租。 笑死贞谓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的葵诈。 我是一名探鬼主播裸弦,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼祟同,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了理疙?” 一聲冷哼從身側(cè)響起晕城,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窖贤,沒想到半個月后砖顷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赃梧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年滤蝠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槽奕。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡几睛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出粤攒,到底是詐尸還是另有隱情所森,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布夯接,位于F島的核電站焕济,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盔几。R本人自食惡果不足惜晴弃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逊拍。 院中可真熱鬧上鞠,春花似錦、人聲如沸芯丧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缨恒。三九已至谴咸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骗露,已是汗流浹背岭佳。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萧锉,地道東北人珊随。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像柿隙,于是被迫代替她去往敵國和親玫恳。 傳聞我的和親對象是個殘疾皇子辨赐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容