給你一個2D的字符矩陣作爲遊戲板。. ‘M’代表未發現的地雷 , ‘E’ 代表着一個未發現的空白區域, ‘B’ 代表一個沒有相鄰(上,下,左,右和所有4個對角線)地雷的空白方塊,數字(’1’至’8’)表示與這個顯示的方形相鄰的地雷數量,最後是’X’ 代表一個已發現的地雷。
現在給出所有未顯示的遊戲版(’M’或’E’)中的下一個點擊位置(行和列索引),根據以下規則顯示該位置後返回主板:
如果一個地雷(’M’)被揭開,那麼這個遊戲結束
如果沒有相鄰地雷的空方塊(’E’)被顯示出來,則將其改爲顯示空白(’B’),並且所有相鄰的未顯示的區域應該遞歸地顯示。
如果與至少有一個相鄰的地雷的方塊(’E’),則將其改爲一個數字(’1’至’8’),表示相鄰地雷的數量。
返回主板,當沒有更多區域可以被打開
Example 1:
Input:
[[‘E’, ‘E’, ‘E’, ‘E’, ‘E’],
[‘E’, ‘E’, ‘M’, ‘E’, ‘E’],
[‘E’, ‘E’, ‘E’, ‘E’, ‘E’],
[‘E’, ‘E’, ‘E’, ‘E’, ‘E’]]
Click : [3,0]
Output:
[[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘M’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
[‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]
Explanation:
Example 2:
Input:
[[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘M’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
[‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]
Click : [1,2]
Output:
[[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘X’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
[‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]
Explanation:
Note:
輸入矩陣的高度和寬度的範圍是[1,50]。
點擊位置只會是未顯示的方塊(’M’或’E’),這也意味着輸入板至少包含一個可點擊的方塊。
輸入板不會是遊戲結束的一個階段(一些地雷被揭示)。
爲了簡單起見,在此問題中不應忽略不提及的規則。 例如,當遊戲結束時,您不需要顯示所有未發現的礦井,考慮任何情況下,您將贏得比賽或標記任何方格。
解決方法
BFS
DFS
BFS解決此問題
public char[][] updateBoard(char[][] board, int[] click) {
// 獲取地圖的長寬
int m = board.length;
int n = board[0].length;
// 廣度優先遍歷 利用隊列
Queue<int[]> queue = new LinkedList<>();
// 將起點加入隊列
queue.add(click);
// 棧不爲空 則未遍歷完全
while (!queue.isEmpty()) {
// 按照隊列先進先出的原則依次遍歷
int[] poll = queue.poll();
int row = poll[0], col = poll[1];
// 點到炸彈區域
if (board[row][col] == 'M') { // Mine
board[row][col] = 'X';
} else {
// 點到非炸彈區域 可能是數字區域也可能是空白區域
int count = 0;
// 將該點的周圍全部訪問
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
// 遍歷到自己
if (i == 0 && j == 0)
continue;
int r = row + i, c = col + j;
// 遍歷超出邊界
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n)
continue;
// 發現有炸彈
if (board[r][c] == 'M' || board[r][c] == 'X')
count++;
}
}
// 如果周圍有炸彈則這個區域不是空白區域 停止BFS
if (count > 0) {
// 該區域周圍的炸彈數量就是該區域的數字大小
board[row][col] = (char) (count + '0');
// 周圍無炸彈 是空白區域
} else {
board[row][col] = 'B';
// 將該區域周圍全部遍歷
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n)
continue;
// 發現未被訪問區域 加入隊列
if (board[r][c] == 'E') {
queue.add(new int[] { r, c });
board[r][c] = 'B';
}
}
}
}
}
}
return board;
}
測試
@Test
public void test() {
char[][] board = { { 'E', 'E', 'E', 'E', 'E' }, { 'E', 'E', 'M', 'E', 'E' }, { 'E', 'E', 'E', 'E', 'E' },
{ 'E', 'E', 'E', 'E', 'E' }, { 'E', 'E', 'E', 'E', 'E' }, { 'E', 'E', 'E', 'E', 'E' } };
for (char[] cs : board) {
for (char c : cs) {
System.out.print(c + " ");
}
System.out.println();
}
System.out.println("-------------");
int[] click = { 3, 0 };
MinesweeperSolutionByBFS minesweeperSolution = new MinesweeperSolutionByBFS();
char[][] updateBoard = minesweeperSolution.updateBoard(board, click);
for (char[] cs : updateBoard) {
for (char c : cs) {
System.out.print(c + " ");
}
System.out.println();
}
}
結果
E E E E E
E E M E E
E E E E E
E E E E E
E E E E E
E E E E E
-------------
B 1 E 1 B
B 1 M 1 B
B 1 1 1 B
B B B B B
B B B B B
B B B B B
DFS方法
public char[][] updateBoard(char[][] board, int[] click) {
int m = board.length, n = board[0].length;
int row = click[0], col = click[1];
// 發現炸彈
if (board[row][col] == 'M') {
board[row][col] = 'X';
// 不是炸彈
} else {
int count = 0;
// 遍歷該區域周圍區域 查找是否有炸彈
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n)
continue;
if (board[r][c] == 'M' || board[r][c] == 'X')
count++;
}
}
// 周圍有炸彈 則該區域不是空白區域 停止 DFS
if (count > 0) {
board[row][col] = (char) (count + '0');
} else {
// 該區域是空白區域
board[row][col] = 'B';
// 遍歷此區域周圍區域
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n)
continue;
// 遇到沒有訪問的區域 開始遞歸訪問
if (board[r][c] == 'E')
updateBoard(board, new int[] { r, c });
}
}
}
}
return board;
}
// 非遞歸版 利用棧
public char[][] updateBoardByStack(char[][] board, int[] click) {
// 創建棧
Stack<int[]> stack = new Stack<>();
int m = board.length, n = board[0].length;
// 將起始點壓入棧
stack.push(click);
// 棧不爲空
while (!stack.isEmpty()) {
int[] peek = stack.peek();
int row = peek[0], col = peek[1];
// 發現炸彈
if (board[row][col] == 'M') {
board[row][col] = 'X';
stack.pop();
// 不是炸彈
} else {
int count = 0;
// 遍歷該區域周圍區域 查找是否有炸彈
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n)
continue;
if (board[r][c] == 'M' || board[r][c] == 'X')
count++;
}
}
// 周圍有炸彈 則該區域不是空白區域 停止 DFS
if (count > 0) {
board[row][col] = (char) (count + '0');
stack.pop();
} else {
// 該區域是空白區域
board[row][col] = 'B';
int[] findNext = findNext(row, col, board);
// 周圍沒有可以訪問的
if (findNext[0] == -1 && findNext[1] == -1)
stack.pop();
else {
stack.push(findNext);
}
}
}
}
return board;
}
//查找下一個可訪問邊
int[] findNext(int row, int col, char[][] board) {
int[] next = { -1, -1 };
// 遍歷此區域周圍區域
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
int r = row + i, c = col + j;
if (r < 0 || r >= board.length || c < 0 || c < 0 || c >= board[0].length)
continue;
// 遇到沒有訪問的區域
if (board[r][c] == 'E') {
next[0] = r;
next[1] = c;
return next;
}
}
}
return next;
}
測試
@Test
public void test() {
char[][] board = { { 'E', 'E', 'E', 'E', 'E' }, { 'E', 'E', 'M', 'E', 'E' }, { 'E', 'E', 'E', 'E', 'E' },
{ 'E', 'E', 'E', 'E', 'E' }, { 'E', 'E', 'E', 'E', 'E' }, { 'E', 'E', 'E', 'E', 'E' } };
for (char[] cs : board) {
for (char c : cs) {
System.out.print(c + " ");
}
System.out.println();
}
System.out.println("-------------");
int[] click = { 3, 0 };
MinesweeperSolutionByDFS minesweeperSolution = new MinesweeperSolutionByDFS();
// 遞歸版
char[][] updateBoard = minesweeperSolution.updateBoard(board, click);
// 非遞歸版
char[][] updateBoardByStack = minesweeperSolution.updateBoardByStack(board, click);
for (char[] cs : updateBoard) {
for (char c : cs) {
System.out.print(c + " ");
}
System.out.println();
}
System.out.println("-------------");
for (char[] cs : updateBoardByStack) {
for (char c : cs) {
System.out.print(c + " ");
}
System.out.println();
}
}
結果
E E E E E
E E M E E
E E E E E
E E E E E
E E E E E
E E E E E
-------------
B 1 E 1 B
B 1 M 1 B
B 1 1 1 B
B B B B B
B B B B B
B B B B B
-------------
B 1 E 1 B
B 1 M 1 B
B 1 1 1 B
B B B B B
B B B B B
B B B B B
到此 掃雷問題差不多就解決了
水平有限 若有錯誤 歡迎指正
關於圖的相關知識可以參考