问题:
扫雷问题:给定一个扫雷地图,
包含:
- M:埋雷cell
- E:空区cell
- X:已被挑出的雷cell
- 1~8:已被扫过的空区cell,该cell四周的埋雷数。
给出扫雷点击坐标click
求,这次click之后的扫雷地图的状态。
变化规则:
- M:变为X,扫到雷,游戏结束。
- E:四周无雷:变为B,再递归扫除四周cell。
- 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']] 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']] 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.
Example 1:
Example 2:
解法:BFS
queue中:从click的cell开始,存入坐标。
- 入队条件:当前cell为E,且四周埋雷数count==0。
- 则将该cell的四周cell入队,
♻️ 优化:为了防止重复入队相同的cell,则在第一次入队时,将该cell设为B。
以后只有cell为E的时候,才入队。
但是当前cell为B的时候,有可能其四周埋雷,需要更新为埋雷数量1~8。
- 终止入队:(当前节点跳过,去处理queue中其他节点)
- cell为M
- or cell四周埋雷数>0。
代码参考:
1 class Solution { 2 public: 3 vector<vector<int>> dir = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}; 4 int n,m; 5 int countM(int i, int j, vector<vector<char>>& board){ 6 int x = 0, y = 0; 7 int count = 0; 8 for(auto d:dir) { 9 x=i+d[0], y=j+d[1]; 10 if(x<0 || y<0 || x>=n || y>=m) continue; 11 if(board[x][y]=='M' || board[x][y]=='X')count++; 12 } 13 return count; 14 } 15 vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) { 16 n = board.size(); 17 m = board[0].size(); 18 if(click[0]<0 || click[1]<0 || click[0]>=n || click[1]>=m) return board; 19 /*vector<vector<int>> markboard(n, vector<int>(m,0)); 20 for(int i=0; i<n; i++) { 21 for(int j=0; j<m; j++) { 22 if(board[i][j]=='M') markM(i,j,markboard, board); 23 } 24 } 25 for(int i=0; i<n; i++) { 26 for(int j=0; j<m; j++) { 27 printf("%d ", markboard[i][j]); 28 } 29 printf(" "); 30 }*/ 31 queue<pair<int, int>> q; 32 q.push({click[0],click[1]}); 33 int cur_x, cur_y, x, y; 34 while(!q.empty()) { 35 int sz = q.size(); 36 for(int i=0; i<sz; i++) { 37 cur_x = q.front().first; 38 cur_y = q.front().second; 39 q.pop(); 40 if(board[cur_x][cur_y]=='M') { 41 board[cur_x][cur_y]='X'; 42 continue; 43 } 44 int cM = countM(cur_x,cur_y,board); 45 if(cM>0) { 46 board[cur_x][cur_y]=cM+'0'; 47 continue; 48 } 49 board[cur_x][cur_y]='B'; 50 for(auto d:dir) { 51 x = cur_x+d[0], y = cur_y+d[1]; 52 //printf("x:%d, y:%d ",x,y); 53 if(x<0 || y<0 || x>=n || y>=m || board[x][y]!='E') continue; 54 //printf("inqueue:(%d,%d)=%c ",x,y,board[x][y]); 55 q.push({x,y}); 56 board[x][y]='B'; 57 //优化,第一次判断立即将该点设为非E,之后其他方向点判断时,直接continue 58 //不用加入queue.保证一个cell只加入queue一次。 59 60 } 61 } 62 } 63 return board; 64 } 65 };