▶ 扫雷的扩展判定。已知棋盘上所有点的情况(雷区 'M',已翻开空白区 'B',未翻开空白区 'E',数字区 '1' ~ '8'),现在给定一个点击位置(一定在空白区域),若命中雷区则将被命中的 M 改为 X,若命中空白区则将点击位置扩展为带有数字边界的安全区。
● 自己的解法,28 ms,深度优先遍历。改善了边界判定的方法,以后写类似的矩阵函数的时候可以借鉴。实际上可以在 extend 开头判定 click 是否在棋盘范围内,以后就可以强行 8 个方向搜索(见后面大佬的代码)
1 class Solution 2 { 3 public: 4 vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) 5 { 6 if (board[click[0]][click[1]] == 'M') 7 { 8 board[click[0]][click[1]] = 'X'; 9 return board; 10 } 11 extend(board, click); 12 return board; 13 } 14 void extend(vector<vector<char>>& board, vector<int>& click) 15 { 16 const int row = board.size(), col = board[0].size(), rowClick = click[0], colClick = click[1]; 17 char location = ~0; 18 int count = 0; 19 vector<int> tempClick; 20 // 计算当前位置的相邻情况,location从左边起 8 位分别表示 右,右上,上,左上,左,左下,下,右下 是否有相邻块 21 if (colClick % col == col - 1) // 右,11000001 22 location &= ~193; 23 if (rowClick == 0) // 上,01110000 24 location &= ~112; 25 if (colClick % col == 0) // 左,00011100 26 location &= ~28; 27 if (rowClick == row - 1) // 下,00000111 28 location &= ~7; 29 // 统计周围雷数计数,从右开始,逆时针方向搜索 30 if (location & 1 << 7 && board[rowClick][colClick + 1] == 'M') 31 count++; 32 if (location & 1 << 6 && board[rowClick - 1][colClick + 1] == 'M') 33 count++; 34 if (location & 1 << 5 && board[rowClick - 1][colClick] == 'M') 35 count++; 36 if (location & 1 << 4 && board[rowClick - 1][colClick - 1] == 'M') 37 count++; 38 if (location & 1 << 3 && board[rowClick][colClick - 1] == 'M') 39 count++; 40 if (location & 1 << 2 && board[rowClick + 1][colClick - 1] == 'M') 41 count++; 42 if (location & 1 << 1 && board[rowClick + 1][colClick] == 'M') 43 count++; 44 if (location & 1 << 0 && board[rowClick + 1][colClick + 1] == 'M') 45 count++; 46 if (count)// 周围有雷,本地为数字,停止搜索 47 { 48 board[rowClick][colClick] = count + '0'; 49 return; 50 } 51 board[rowClick][colClick] = 'B';// 周围无雷,本地为安全区,继续搜索 52 if (location & 1 << 7 && board[rowClick][colClick + 1] == 'E') 53 extend(board, tempClick = { rowClick, colClick + 1 }); 54 if (location & 1 << 6 && board[rowClick - 1][colClick + 1] == 'E') 55 extend(board, tempClick = { rowClick - 1, colClick + 1 }); 56 if (location & 1 << 5 && board[rowClick - 1][colClick] == 'E') 57 extend(board, tempClick = { rowClick - 1, colClick }); 58 if (location & 1 << 4 && board[rowClick - 1][colClick - 1] == 'E') 59 extend(board, tempClick = { rowClick - 1, colClick - 1 }); 60 if (location & 1 << 3 && board[rowClick][colClick - 1] == 'E') 61 extend(board, tempClick = { rowClick, colClick - 1 }); 62 if (location & 1 << 2 && board[rowClick + 1][colClick - 1] == 'E') 63 extend(board, tempClick = { rowClick + 1, colClick - 1 }); 64 if (location & 1 << 1 && board[rowClick + 1][colClick] == 'E') 65 extend(board, tempClick = { rowClick + 1, colClick }); 66 if (location & 1 << 0 && board[rowClick + 1][colClick + 1] == 'E') 67 extend(board, tempClick = { rowClick + 1, colClick + 1 }); 68 return; 69 } 70 };
● 大佬的代码,38 ms,深度优先遍历,与后面的广度优先遍历在格式上保持一致
1 class Solution 2 { 3 public: 4 vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) 5 { 6 int m = board.size(), n = board[0].size(), row = click[0], col = click[1]; 7 int count, i, j, r, c; 8 vector<int>tempClick; 9 if (board[row][col] == 'M') 10 { 11 board[row][col] = 'X'; 12 return board; 13 } 14 for (count = 0, i = -1; i < 2; i++) 15 { 16 for (j = -1; j < 2; j++) 17 { 18 if (i == 0 && j == 0) 19 continue; 20 r = row + i, c = col + j; 21 if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) 22 continue; 23 if (board[r][c] == 'M' || board[r][c] == 'X') 24 count++; 25 } 26 } 27 if (count) 28 { 29 board[row][col] = (char)(count + '0'); 30 return board; 31 } 32 for (board[row][col] = 'B', i = -1; i < 2; i++) 33 { 34 for (j = -1; j < 2; j++) 35 { 36 if (i == 0 && j == 0) 37 continue; 38 r = row + i, c = col + j; 39 if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) 40 continue; 41 if (board[r][c] == 'E') 42 updateBoard(board, tempClick = { r, c }); 43 } 44 } 45 return board; 46 } 47 };
● 大佬的广度优先遍历,31 ms,最快的解法算法与之相同,但维护一个 unordered_set<int> 用于保存已经访问过的点来防止重复访问
1 class Solution 2 { 3 public: 4 vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) 5 { 6 const int m = board.size(), n = board[0].size(); 7 queue<vector<int>> q; 8 vector<int> cell; 9 int row, col, count, i, j, r, c; 10 for (q.push(click); !q.empty();) 11 { 12 cell = q.front(),q.pop(); 13 row = cell[0], col = cell[1]; 14 if (board[row][col] == 'M') 15 { 16 board[row][col] = 'X'; 17 continue; 18 } 19 for (count = 0, i = -1; i < 2; i++) 20 { 21 for (j = -1; j < 2; j++) 22 { 23 if (i == 0 && j == 0) 24 continue; 25 r = row + i, c = col + j; 26 if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) 27 continue; 28 if (board[r][c] == 'M' || board[r][c] == 'X') 29 count++; 30 } 31 } 32 if (count) 33 { 34 board[row][col] = (char)(count + '0'); 35 continue; 36 } 37 for (board[row][col] = 'B', i = -1; i < 2; i++) 38 { 39 for (j = -1; j < 2; j++) 40 { 41 if (i == 0 && j == 0) 42 continue; 43 r = row + i, c = col + j; 44 if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) 45 continue; 46 if (board[r][c] == 'E') 47 { 48 q.push(vector<int>{r, c}); 49 board[r][c] = 'B'; 50 } 51 } 52 } 53 } 54 return board; 55 } 56 };