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 + ")"; } } }