529. Minesweeper
Problem Description
Let's play the minesweeper game! You are given an m x n char matrix board representing the game board where:
'M'represents an unrevealed mine'E'represents an unrevealed empty square'B'represents a revealed blank square that has no adjacent mines (i.e., above, below, left, right, and all 4 diagonals)- digit (
'1'to'8') represents how many mines are adjacent to this revealed square 'X'represents a revealed mine
You are also given an integer array click where click = [clickr, clickc] represents the next click position 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: board = [["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: board = [["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"]]
Constraints:
m == board.lengthn == board[i].length1 <= m, n <= 50board[i][j]is either'M','E','B', or a digit from'1'to'8'.click.length == 20 <= clickr < m0 <= clickc < nboard[clickr][clickc]is either'M'or'E'.
Solution
Python Solution
class Solution:
def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]:
if not board:
return board
m, n = len(board), len(board[0])
row, col = click[0], click[1]
# If a mine is revealed, game over
if board[row][col] == 'M':
board[row][col] = 'X'
return board
def countMines(r: int, c: int) -> int:
count = 0
for i in range(max(0, r-1), min(m, r+2)):
for j in range(max(0, c-1), min(n, c+2)):
if board[i][j] == 'M':
count += 1
return count
def dfs(r: int, c: int):
if r < 0 or r >= m or c < 0 or c >= n or board[r][c] != 'E':
return
mines = countMines(r, c)
if mines == 0:
board[r][c] = 'B'
for i in range(max(0, r-1), min(m, r+2)):
for j in range(max(0, c-1), min(n, c+2)):
dfs(i, j)
else:
board[r][c] = str(mines)
dfs(row, col)
return board
Time Complexity: O(m*n)
Where m and n are the dimensions of the board. In worst case, we might need to reveal all cells.
Space Complexity: O(m*n)
For the recursion stack in worst case when revealing all cells.
Java Solution
class Solution {
private int m, n;
public char[][] updateBoard(char[][] board, int[] click) {
if (board == null || board.length == 0) {
return board;
}
m = board.length;
n = board[0].length;
int row = click[0], col = click[1];
// If a mine is revealed, game over
if (board[row][col] == 'M') {
board[row][col] = 'X';
return board;
}
dfs(board, row, col);
return board;
}
private void dfs(char[][] board, int r, int c) {
if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] != 'E') {
return;
}
int mines = countMines(board, r, c);
if (mines == 0) {
board[r][c] = 'B';
for (int i = Math.max(0, r-1); i < Math.min(m, r+2); i++) {
for (int j = Math.max(0, c-1); j < Math.min(n, c+2); j++) {
dfs(board, i, j);
}
}
} else {
board[r][c] = (char)(mines + '0');
}
}
private int countMines(char[][] board, int r, int c) {
int count = 0;
for (int i = Math.max(0, r-1); i < Math.min(m, r+2); i++) {
for (int j = Math.max(0, c-1); j < Math.min(n, c+2); j++) {
if (board[i][j] == 'M') {
count++;
}
}
}
return count;
}
}
Time Complexity: O(m*n)
Where m and n are the dimensions of the board. In worst case, we might need to reveal all cells.
Space Complexity: O(m*n)
For the recursion stack in worst case when revealing all cells.
C++ Solution
class Solution {
private:
int m, n;
int countMines(vector>& board, int r, int c) {
int count = 0;
for (int i = max(0, r-1); i < min(m, r+2); i++) {
for (int j = max(0, c-1); j < min(n, c+2); j++) {
if (board[i][j] == 'M') {
count++;
}
}
}
return count;
}
void dfs(vector>& board, int r, int c) {
if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] != 'E') {
return;
}
int mines = countMines(board, r, c);
if (mines == 0) {
board[r][c] = 'B';
for (int i = max(0, r-1); i < min(m, r+2); i++) {
for (int j = max(0, c-1); j < min(n, c+2); j++) {
dfs(board, i, j);
}
}
} else {
board[r][c] = mines + '0';
}
}
public:
vector> updateBoard(vector>& board, vector& click) {
if (board.empty()) {
return board;
}
m = board.size();
n = board[0].size();
int row = click[0], col = click[1];
// If a mine is revealed, game over
if (board[row][col] == 'M') {
board[row][col] = 'X';
return board;
}
dfs(board, row, col);
return board;
}
};
Time Complexity: O(m*n)
Where m and n are the dimensions of the board. In worst case, we might need to reveal all cells.
Space Complexity: O(m*n)
For the recursion stack in worst case when revealing all cells.
JavaScript Solution
/**
* @param {character[][]} board
* @param {number[]} click
* @return {character[][]}
*/
var updateBoard = function(board, click) {
if (!board.length) {
return board;
}
const m = board.length;
const n = board[0].length;
const [row, col] = click;
// If a mine is revealed, game over
if (board[row][col] === 'M') {
board[row][col] = 'X';
return board;
}
const countMines = (r, c) => {
let count = 0;
for (let i = Math.max(0, r-1); i < Math.min(m, r+2); i++) {
for (let j = Math.max(0, c-1); j < Math.min(n, c+2); j++) {
if (board[i][j] === 'M') {
count++;
}
}
}
return count;
};
const dfs = (r, c) => {
if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] !== 'E') {
return;
}
const mines = countMines(r, c);
if (mines === 0) {
board[r][c] = 'B';
for (let i = Math.max(0, r-1); i < Math.min(m, r+2); i++) {
for (let j = Math.max(0, c-1); j < Math.min(n, c+2); j++) {
dfs(i, j);
}
}
} else {
board[r][c] = mines.toString();
}
};
dfs(row, col);
return board;
};
Time Complexity: O(m*n)
Where m and n are the dimensions of the board. In worst case, we might need to reveal all cells.
Space Complexity: O(m*n)
For the recursion stack in worst case when revealing all cells.
C# Solution
public class Solution {
private int m, n;
public char[][] UpdateBoard(char[][] board, int[] click) {
if (board == null || board.Length == 0) {
return board;
}
m = board.Length;
n = board[0].Length;
int row = click[0], col = click[1];
// If a mine is revealed, game over
if (board[row][col] == 'M') {
board[row][col] = 'X';
return board;
}
DFS(board, row, col);
return board;
}
private void DFS(char[][] board, int r, int c) {
if (r < 0 || r >= m || c < 0 || c >= n || board[r][c] != 'E') {
return;
}
int mines = CountMines(board, r, c);
if (mines == 0) {
board[r][c] = 'B';
for (int i = Math.Max(0, r-1); i < Math.Min(m, r+2); i++) {
for (int j = Math.Max(0, c-1); j < Math.Min(n, c+2); j++) {
DFS(board, i, j);
}
}
} else {
board[r][c] = (char)(mines + '0');
}
}
private int CountMines(char[][] board, int r, int c) {
int count = 0;
for (int i = Math.Max(0, r-1); i < Math.Min(m, r+2); i++) {
for (int j = Math.Max(0, c-1); j < Math.Min(n, c+2); j++) {
if (board[i][j] == 'M') {
count++;
}
}
}
return count;
}
}
Time Complexity: O(m*n)
Where m and n are the dimensions of the board. In worst case, we might need to reveal all cells.
Space Complexity: O(m*n)
For the recursion stack in worst case when revealing all cells.
Approach Explanation
The solution uses DFS to reveal cells recursively:
- Key Insights:
- DFS traversal
- Adjacent counting
- Boundary checking
- State tracking
- Algorithm Steps:
- Check mine hit
- Count adjacent mines
- Reveal recursively
- Update board state
Implementation Details:
- DFS implementation
- Mine counting
- Board updates
- Boundary handling
Optimization Insights:
- Early termination
- Boundary checks
- State tracking
- Memory usage
Edge Cases:
- Empty board
- Mine hit
- Board edges
- No adjacent mines