题目
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.
类似扫雷游戏,初始点击位置一定是有效的,遵循四条规则进行点击:
1.翻开为M,改为X,游戏结束。
2.翻开为E,如果所有邻居中没有找到M,将E改为B,并把相邻未翻开的位置记录下来,下次进行点击。
3.翻开E,如果周围至少有一个M,将E改为周围存在的雷数。
4.当没有要点击的位置之后返回白板。
比较慢的一个版本代码是分别写函数寻找上方,下方,左侧,右侧的位置,并且也是邻居为E时保存位置,不过因为直接保存到了click中,因此总会有erase操作,时间会很慢,另外一个版本是宽度优先遍历,用两个for循环代表坐标从-1,+0,+1变化,并且用临时变量保存邻居信息,只有需要保存的时候才会压入,减少了很多erase操作。
class Solution {
public:
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
deque<pair<int, int>> q({ { click[0], click[1] } });//用队列保存点击位置
while (!q.empty()) {
auto c = q.front().first, r = q.front().second, mines = 0;
vector<pair<int, int>> neighbours;//用向量保存邻居位置
if (board[c][r] == 'M') board[c][r] = 'X';
else for (auto i = -1; i <= 1; ++i) {//横纵坐标从当前位置分别-1,+0,+1覆盖八个方向
for (auto j = -1; j <= 1; ++j) {
if (c + i >= 0 && r + j >= 0 && c + i < board.size() && r + j < board[0].size()) {//判断是否越界
if (board[c + i][r + j] == 'M') ++mines;
else if (mines == 0 && board[c + i][r + j] == 'E') neighbours.push_back({ c + i, r + j});//如果没找到雷并且邻居是空,则保存邻居位置
}
}
}
if (mines > 0) board[c][r] = '0' + mines;//根据雷的数量决定点击位置的信息
else for (auto n : neighbours) {
board[n.first][n.second] = 'B';
q.push_back(n);
}
q.pop_front();
}
return board;
}
};