環繞區域

原題

  Given a 2D board containing 'X' and '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,java

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

 

 

題目大意

  一個二維網格,包含’X’與’O’,將因此被X包圍的O區域用X替代,返回替代後後結果。數組

解題思路

  採用廣度優先遍歷的方式,(也能夠採用嘗試深度優先的方式(會有棧溢出)),標記出全部的被包圍的點,剩下的就是不被包圍的點ide

代碼實現

算法實現類this

import java.util.LinkedList;
import java.util.List;

public class Solution {    
    ////////////////////////////////////////////////////////////////////////////////////////////////
    // 下面採用廣度度優先遍歷的方式,找出全部的【不】被包圍的點
    ////////////////////////////////////////////////////////////////////////////////////////////////
    public void solve(char[][] board) {
        // 參數校驗
        if (board == null || board.length < 1 || board[0].length < 1) {
            return;
        }

        boolean[][] visited = new boolean[board.length][board[0].length];
        // 廣度優先搜索時外圍一圈的元素
        List<Coordinate> round = new LinkedList<>();
        // 處理頂部行
        for (int col = 0; col < board[0].length; col++) {
            // 頂部行,而且點是O而且點未被訪問過
            if (!visited[0][col] && board[0][col] == 'O') {
                round.clear();
                round.add(new Coordinate(0, col));
                bfs(board, visited, round);
            }
        }

        // 處理底部行
        for (int col = 0; col < board[0].length; col++) {
            // 頂部行,而且點是O而且點未被訪問過
            if (!visited[board.length - 1][col] && board[board.length - 1][col] == 'O') {
                round.clear();
                round.add(new Coordinate(board.length - 1, col));
                bfs(board, visited, round);
            }
        }

        // 處理左邊列
        for (int row = 1; row < board.length - 1; row++) {
            // 頂部行,而且點是O而且點未被訪問過
            if (!visited[row][0] && board[row][0] == 'O') {
                round.clear();
                round.add(new Coordinate(row, 0));
                bfs(board, visited, round);
            }
        }

        // 處理右邊列
        for (int row = 1; row < board.length - 1; row++) {
            // 頂部行,而且點是O而且點未被訪問過
            if (!visited[row][board[0].length - 1] && board[row][board[0].length - 1] == 'O') {
                round.clear();
                round.add(new Coordinate(row, board[0].length - 1));
                bfs(board, visited, round);
            }
        }

        // 標記網格
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                // 若是未被訪問過,有兩種可能,第一是X點,第二是O點,O點必定是被X包圍的
                // 此時將未訪問過的點設置爲X是正確的
                if (!visited[i][j]) {
                    board[i][j] = 'X';
                }
            }
        }
    }

    /**
     * 深度優先,找不被包圍的點
     *
     * @param board   二維網格
     * @param visited 訪問標記數組
     * @param round   廣度優先搜索時外圍一圈的元素
     */
    public void bfs(char[][] board, boolean[][] visited, List<Coordinate> round) {
        Coordinate c;
        while (round.size() > 0) {
            c = round.remove(0);
            if (c.x >= 0 && c.x < board.length && c.y >= 0 && c.y < board[0].length && board[c.x][c.y] == 'O' && !visited[c.x][c.y]) {
                visited[c.x][c.y] = true;
                round.add(new Coordinate(c.x - 1, c.y));
                round.add(new Coordinate(c.x, c.y + 1));
                round.add(new Coordinate(c.x + 1, c.y));
                round.add(new Coordinate(c.x, c.y - 1));
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // 下面採用廣度度優先遍歷的方式,找出全部的被包圍的點,而且標記會超時
    ////////////////////////////////////////////////////////////////////////////////////////////////
    public void solve2(char[][] board) {
        // 參數校驗
        if (board == null || board.length < 1 || board[0].length < 1) {
            return;
        }

        boolean[][] visited = new boolean[board.length][board[0].length];

        // 廣度優先搜索時外圍一圈的元素
        List<Coordinate> round = new LinkedList<>();
        // 廣度優先搜索進的全部元素
        List<Coordinate> all = new LinkedList<>();

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (!visited[i][j] && board[i][j] == 'O') {
                    // 廣度優先搜索第一圈的元素
                    round.add(new Coordinate(i, j));
                    boolean result = bfs(board, visited, round, all);
                    // 一次搜索的全部O都在網格內,而且不在邊界上
                    if (result) {
                        // 設置標記
                        for (Coordinate c : all) {
                            board[c.x][c.y] = 'X';
                        }
                    }

                    // 清空元素
                    round.clear();
                    all.clear();
                }
            }
        }

    }

    /**
     * 廣度優先遍歷
     *
     * @param board   二維網格
     * @param visited 訪問標記數組
     * @param round   廣度優先搜索時外圍一圈的元素
     * @param all     廣度優先搜索進的全部元素
     * @return true點是O,點在網格內,而且不在邊界上,若是點是X,總返回true
     */
    public boolean bfs(char[][] board, boolean[][] visited, List<Coordinate> round, List<Coordinate> all) {
        boolean result = true;
        int size = round.size();
        Coordinate c;
        while (size > 0) {
            size--;

            // 取隊首元素
            c = round.remove(0);
            // 添加到遍歷記錄元素集合中
            all.add(c);
            // 標記已經被訪問過了
            visited[c.x][c.y] = true;
            // 判斷c是不是O內點
            result &= isInner(board, c.x, c.y);

            // c的上面一個點是不是O,而且沒有訪問過,知足就添加到round隊列中
            if (isO(board, c.x - 1, c.y) && !visited[c.x - 1][c.y]) {
                round.add(new Coordinate(c.x - 1, c.y));
            }

            // c的右面一個點是不是O,而且沒有訪問過,知足就添加到round隊列中
            if (isO(board, c.x, c.y + 1) && !visited[c.x][c.y + 1]) {
                round.add(new Coordinate(c.x, c.y + 1));
            }

            // c的下面一個點是不是O,而且沒有訪問過,知足就添加到round隊列中
            if (isO(board, c.x + 1, c.y) && !visited[c.x + 1][c.y]) {
                round.add(new Coordinate(c.x + 1, c.y));
            }

            // c的左面一個點是不是O,而且沒有訪問過,知足就添加到round隊列中
            if (isO(board, c.x, c.y - 1) && !visited[c.x][c.y - 1]) {
                round.add(new Coordinate(c.x, c.y - 1));
            }
        }

        if (round.size() > 0) {
            return bfs(board, visited, round, all) && result;
        } else {
            return result;
        }

    }

    /**
     * 判斷點在二維風格內部,而且不在邊界上
     *
     * @param board 二維網格
     * @param x     橫座標
     * @param y     縱座標
     * @return true是
     */
    public boolean isInner(char[][] board, int x, int y) {
        return x > 0 && x < board.length - 1 && y > 0 && y < board[0].length - 1;
    }

    /**
     * 判斷點是不是O
     *
     * @param board 二維網格
     * @param x     橫座標
     * @param y     縱座標
     * @return true是
     */
    public boolean isO(char[][] board, int x, int y) {
        return x >= 0 && x < board.length && y >= 0 && y < board[0].length && board[x][y] == 'O';
    }

    /**
     * 座標對象
     */
    public static class Coordinate {
        private int x;
        private int y;

        public Coordinate() {
        }

        public Coordinate(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return "(" + x + ", " + y + ")";
        }
    }
}
相關文章
相關標籤/搜索