[리트코드] 529 - Minesweeper
2026년 07월 24일
1
529. Minesweeper
Medium
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 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'.
분류
배열, 깊이 우선 탐색, 너비 우선 탐색, 행렬
문제 풀이
문제 분석
이 문제는 지뢰찾기 게임의 한 턴을 시뮬레이션하는 것입니다.
입력으로 게임 보드(board)와 클릭한 위치(click)가 주어집니다. 보드는 'M'(지뢰), 'E'(미공개 빈 칸), 'B'(공개된 빈 칸), '1'~'8'(주변 지뢰 수), 'X'(공개된 지뢰) 문자로 구성됩니다.
규칙에 따라 클릭한 위치를 공개하고, 연쇄적으로 공개되어야 할 칸들을 모두 업데이트한 최종 보드를 반환해야 합니다.
접근 방법
너비 우선 탐색(BFS) 알고리즘을 사용했습니다.
이유는 다음과 같습니다.
- 클릭한 위치에서 시작하여 인접한 칸들을 단계적으로 탐색해야 합니다.
- 주변에 지뢰가 없는 칸('B')일 경우에만 인접한 미공개 칸('E')을 큐에 넣어 계속 탐색을 이어가야 합니다.
- 큐(Queue) 자료구조를 사용하면 현재 공개된 칸에서 인접 칸들을 순차적으로 처리하기에 적절합니다.
또한, **방문 배열(visited)**을 따로 두어 이미 처리한 칸을 다시 큐에 넣지 않도록 하여 중복 연산을 방지하고 무한 루프를 예방했습니다.
구현 설명
1. 초기 클릭 처리 및 지뢰 클릭 시 예외 처리
- 클릭 좌표(
cx,cy)를 꺼냅니다. - 해당 위치가 지뢰('M')라면 즉시 'X'로 변경하고 보드를 반환하여 게임을 종료시킵니다.
2. BFS 탐색 준비
- 방문 여부를 기록할 2차원 배열
visited를 생성하고, 시작 위치를True로 표시합니다. - 8방향(상하좌우, 대각선) 탐색을 위한 방향 배열
check_x,check_y를 정의합니다. - 시작 좌표를 큐(
deque)에 넣고 탐색을 시작합니다.
3. 큐 순회 및 주변 지뢰 개수 세기
- 큐에서 좌표
(x, y)를 꺼냅니다. - 8방향으로 인접 칸을 확인하며 보드 범위 내에 있고 지뢰('M')인 칸의 개수(
cnt)를 셉니다.
4. 지뢰 개수에 따른 칸 업데이트 및 탐색 확장
- 주변 지뢰가 0개인 경우 (
cnt == 0):- 현재 칸을 'B'로 변경합니다.
- 다시 8방향을 돌며, 범위 내에 있고 **미방문 상태이며 미공개 빈 칸('E')**인 인접 칸들을 큐에 추가하고 방문 처리합니다. (연쇄 공개)
- 주변 지뢰가 1개 이상인 경우 (
cnt > 0):- 현재 칸을 숫자 문자열(
str(cnt))로 변경합니다. - 인접 칸을 큐에 넣지 않고 탐색을 중단합니다. (숫자 칸에서는 더 이상 확장하지 않음)
- 현재 칸을 숫자 문자열(
⏱복잡도 분석
- 시간 복잡도: O(m × n)
m은 행의 수,n은 열의 수입니다. 최악의 경우 보드 전체 칸을 한 번씩 방문하며, 각 칸에서 상수 연산(8방향 확인)을 수행하므로 O(m × n)입니다. - 공간 복잡도: O(m × n)
방문 배열visited가 O(m × n) 크기를 차지하고, 큐 역시 최악의 경우 모든 칸이 들어갈 수 있어 O(m × n)의 추가 공간이 필요합니다.
핵심 포인트
- 클릭 즉시 지뢰('M')면 게임 종료: 별도 탐색 없이 'X'로 바꾸고 바로 리턴해야 합니다.
- 'E'에서 'B'로 바뀔 때만 BFS 확장: 주변 지뢰가 0개여야 인접 칸을 큐에 넣습니다. 숫자가 표시되는 칸('1'~'8')은 탐색의 끝 지점이 됩니다.
- 방문 배열(
visited) 필수: 방문 처리를 큐에 넣을 때(append시점)에 해야 중복 삽입을 막을 수 있습니다. 꺼낼 때(popleft시점)에 하면 같은 칸이 큐에 여러 번 들어갈 수 있습니다.
풀이 코드
from collections import deque
class Solution:
def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]:
n = len(board)
m = len(board[0])
cx,cy = click
if board[cx][cy] == "M":
board[cx][cy] = "X"
return board
visited =[[False] * m for i in range(n)]
visited[cx][cy] = True
check_x = [-1,0,1]
check_y = [-1,0,1]
queue = deque([(cx,cy)])
while queue:
x,y = queue.popleft()
cnt = 0
for dx in check_x:
for dy in check_y:
sx,sy = x+dx,y+dy
if 0<=sx<n and 0<=sy<m:
if board[sx][sy] == "M":
cnt += 1
if cnt == 0:
board[x][y] = "B"
for dx in check_x:
for dy in check_y:
sx,sy = x+dx,y+dy
if 0<=sx<n and 0<=sy<m and not visited[sx][sy] and board[sx][sy] == "E":
queue.append((sx,sy))
visited[sx][sy] = True
else:
board[x][y] = str(cnt)
return board
댓글을 불러오는 중...