Let's play the minesweeper game (Wikipedia, online game)!
You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine.
Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the board after revealing this position according to the following rules:
- If a mine ('M') is revealed, then the game is over - change it to 'X'.
- If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its adjacent unrevealed squares should be revealed recursively.
- If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines.
- Return the board when no more squares will be revealed.
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:
- The range of the input matrix's height and width is [1,50].
- The click position will only be an unrevealed square ('M' or 'E'), which also means the input board contains at least one clickable square.
- The input board won't be a stage when game is over (some mines have been revealed).
- For simplicity, not mentioned rules should be ignored in this problem. For example, you don't need to reveal all the unrevealed mines when the game is over, consider any cases that you will win the game or flag any squares.
扫雷游戏。游戏本身我们小时候应该都玩过,我这里提炼以下题目里面的字母和规则吧。
- M - 未发现的雷
- E - 未发现的空白方块
- B - 发现的空白方块
- 数字 1 - 8
- X - 发现了的雷
这个题我做的时候个人觉得规则解释的不是非常明确,虽然题目说了没有提到的规则可以被忽略(Note 4)。题目给的是二维矩阵board和其中的某一个坐标click。如果当前click位置上点开是个雷,把他mark成X,然后直接就返回board了。例子二把周围的八个坐标mark成了1,但是如果你只是mark了雷而不mark那些1,也是可以的。另外,比如第一个例子,点开的坐标背后是一个B,但是实际题目要求你是递归地遍历完整个board,这个跟我们小时候玩游戏的时候有一点区别,因为他点一次,直接就要求你把整个board的结果返回了。但是雷正上方的那个坐标却依然保持了E。这个坐标保持E的原因是在于DFS遍历的时候先找到了雷所以就直接返回board了,还没来得及去看那个坐标。
回到这道题的解题思路上。既然题目提示了recursively,那么我们试着用DFS做。不过这道题不同于一般的DFS题,需要遍历当前坐标周围的八个邻居。
- 如果当前坐标是雷,标记成X,立马返回board
- 如果当前坐标不是雷,遍历其八个邻居,计算一下有几个雷,把雷的数量写在当前坐标上,返回board
- 如果当前坐标是blank/E,则把当前坐标改成B,然后递归去看他的八个邻居
时间O(mn)
空间O(n)
Java实现
1 class Solution { 2 private int[][] dirs = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 }, { -1, -1 }, { 1, 1 }, { 1, -1 }, { -1, 1 } }; 3 4 public char[][] updateBoard(char[][] board, int[] click) { 5 int row = click[0]; 6 int col = click[1]; 7 int m = board.length; 8 int n = board[0].length; 9 10 // if current position is a bomb 11 if (board[row][col] == 'M') { 12 board[row][col] = 'X'; 13 return board; 14 } 15 16 // count the number of bombs 17 int num = 0; 18 for (int[] dir : dirs) { 19 int newRow = dir[0] + row; 20 int newCol = dir[1] + col; 21 if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && board[newRow][newCol] == 'M') { 22 num++; 23 } 24 } 25 26 // mark the number of bombs around, then return 27 if (num > 0) { 28 board[row][col] = (char) (num + '0'); 29 return board; 30 } 31 32 // if no bomb, mark it as blank 33 board[row][col] = 'B'; 34 for (int[] dir : dirs) { 35 int newRow = dir[0] + row; 36 int newCol = dir[1] + col; 37 if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && board[newRow][newCol] == 'E') { 38 updateBoard(board, new int[] { newRow, newCol }); 39 } 40 } 41 return board; 42 } 43 }