LeetCodee

529. Minesweeper

Jump to Solution: Python Java C++ JavaScript C#

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:

  1. If a mine ('M') is revealed, then the game is over - change it to 'X'.
  2. 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.
  3. 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.
  4. 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.length
  • n == board[i].length
  • 1 <= m, n <= 50
  • board[i][j] is either 'M', 'E', 'B', or a digit from '1' to '8'.
  • click.length == 2
  • 0 <= clickr < m
  • 0 <= clickc < n
  • board[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:

  1. Key Insights:
    • DFS traversal
    • Adjacent counting
    • Boundary checking
    • State tracking
  2. 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