Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
Let's play the minesweeper game (Wikipedia, online 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),'1' to '8') represents how many mines are adjacent to this revealed square, and'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:
'M' is revealed, then the game is over. You should change it to 'X'.'E' with no adjacent mines is revealed, then change it to a revealed blank 'B' and all of its adjacent unrevealed squares should be revealed recursively.'E' with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines.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'.Problem summary: Let's play the minesweeper game (Wikipedia, online 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, and '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. You should change it to 'X'. If an empty square 'E' with no adjacent mines is revealed, then change it to a revealed blank 'B' and all of its adjacent
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
[["E","E","E","E","E"],["E","E","M","E","E"],["E","E","E","E","E"],["E","E","E","E","E"]] [3,0]
[["B","1","E","1","B"],["B","1","M","1","B"],["B","1","1","1","B"],["B","B","B","B","B"]] [1,2]
detonate-the-maximum-bombs)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #529: Minesweeper
class Solution {
private char[][] board;
private int m;
private int n;
public char[][] updateBoard(char[][] board, int[] click) {
m = board.length;
n = board[0].length;
this.board = board;
int i = click[0], j = click[1];
if (board[i][j] == 'M') {
board[i][j] = 'X';
} else {
dfs(i, j);
}
return board;
}
private void dfs(int i, int j) {
int cnt = 0;
for (int x = i - 1; x <= i + 1; ++x) {
for (int y = j - 1; y <= j + 1; ++y) {
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M') {
++cnt;
}
}
}
if (cnt > 0) {
board[i][j] = (char) (cnt + '0');
} else {
board[i][j] = 'B';
for (int x = i - 1; x <= i + 1; ++x) {
for (int y = j - 1; y <= j + 1; ++y) {
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E') {
dfs(x, y);
}
}
}
}
}
}
// Accepted solution for LeetCode #529: Minesweeper
func updateBoard(board [][]byte, click []int) [][]byte {
m, n := len(board), len(board[0])
i, j := click[0], click[1]
var dfs func(i, j int)
dfs = func(i, j int) {
cnt := 0
for x := i - 1; x <= i+1; x++ {
for y := j - 1; y <= j+1; y++ {
if x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M' {
cnt++
}
}
}
if cnt > 0 {
board[i][j] = byte(cnt + '0')
return
}
board[i][j] = 'B'
for x := i - 1; x <= i+1; x++ {
for y := j - 1; y <= j+1; y++ {
if x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E' {
dfs(x, y)
}
}
}
}
if board[i][j] == 'M' {
board[i][j] = 'X'
} else {
dfs(i, j)
}
return board
}
# Accepted solution for LeetCode #529: Minesweeper
class Solution:
def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]:
def dfs(i: int, j: int):
cnt = 0
for x in range(i - 1, i + 2):
for y in range(j - 1, j + 2):
if 0 <= x < m and 0 <= y < n and board[x][y] == "M":
cnt += 1
if cnt:
board[i][j] = str(cnt)
else:
board[i][j] = "B"
for x in range(i - 1, i + 2):
for y in range(j - 1, j + 2):
if 0 <= x < m and 0 <= y < n and board[x][y] == "E":
dfs(x, y)
m, n = len(board), len(board[0])
i, j = click
if board[i][j] == "M":
board[i][j] = "X"
else:
dfs(i, j)
return board
// Accepted solution for LeetCode #529: Minesweeper
struct Solution;
use std::collections::VecDeque;
struct Point {
i: usize,
j: usize,
}
macro_rules! point {
($i:expr,$j:expr) => {
Point { i: $i, j: $j }
};
}
impl Point {
fn adj(&self, n: usize, m: usize) -> Vec<Point> {
let mut res: Vec<Point> = vec![];
for i in -1..=1 {
for j in -1..=1 {
let r = self.i as i32 + i;
let c = self.j as i32 + j;
if r < 0 || r > (n - 1) as i32 || c < 0 || c > (m - 1) as i32 {
continue;
}
res.push(point!(r as usize, c as usize))
}
}
res
}
}
impl Solution {
fn update_board(mut board: Vec<Vec<char>>, click: Vec<i32>) -> Vec<Vec<char>> {
let n = board.len();
let m = board[0].len();
let i = click[0] as usize;
let j = click[1] as usize;
if board[i][j] == 'M' {
board[i][j] = 'X';
return board;
}
let mut visited: Vec<Vec<bool>> = vec![vec![false; m]; n];
let mut queue: VecDeque<Point> = VecDeque::new();
queue.push_back(Point { i, j });
while let Some(p) = queue.pop_front() {
visited[p.i][p.j] = true;
if board[p.i][p.j] == 'E' {
let mut sum = 0;
for q in p.adj(n, m) {
if board[q.i][q.j] == 'M' {
sum += 1;
}
}
if sum == 0 {
board[p.i][p.j] = 'B';
for q in p.adj(n, m) {
if !visited[q.i][q.j] {
queue.push_back(q);
}
}
} else {
board[p.i][p.j] = (b'0' + sum) as char;
}
}
}
board
}
}
#[test]
fn test() {
let board = vec_vec_char![
['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'M', 'E', 'E'],
['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'E', 'E', 'E']
];
let click = vec![3, 0];
let res = vec_vec_char![
['B', '1', 'E', '1', 'B'],
['B', '1', 'M', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']
];
assert_eq!(Solution::update_board(board, click), res);
}
// Accepted solution for LeetCode #529: Minesweeper
function updateBoard(board: string[][], click: number[]): string[][] {
const m = board.length;
const n = board[0].length;
const [i, j] = click;
const dfs = (i: number, j: number) => {
let cnt = 0;
for (let x = i - 1; x <= i + 1; ++x) {
for (let y = j - 1; y <= j + 1; ++y) {
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] === 'M') {
++cnt;
}
}
}
if (cnt > 0) {
board[i][j] = cnt.toString();
return;
}
board[i][j] = 'B';
for (let x = i - 1; x <= i + 1; ++x) {
for (let y = j - 1; y <= j + 1; ++y) {
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] === 'E') {
dfs(x, y);
}
}
}
};
if (board[i][j] === 'M') {
board[i][j] = 'X';
} else {
dfs(i, j);
}
return board;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.