代码改变世界

[LeetCode] 529. Minesweeper_ Medium_ tag: BFS

2018-07-03 06:04  Johnson_强生仔仔  阅读(290)  评论(0编辑  收藏  举报

Let's play the minesweeper game (Wikipediaonline game)!

You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine.

Now given the next click position (row and column indices) 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: 

[['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']]

Explanation:

 

Example 2:

Input: 

[['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']]

Explanation:

 

 

Note:

  1. The range of the input matrix's height and width is [1,50].
  2. The click position will only be an unrevealed square ('M' or 'E'), which also means the input board contains at least one clickable square.
  3. The input board won't be a stage when game is over (some mines have been revealed).
  4. For simplicity, not mentioned rules should be ignored in this problem. For example, you don't need to reveal all the unrevealed mines when the game is over, consider any cases that you will win the game or flag any squares.

 

这一题乍一看好像蛮复杂的, 但实际上就是BFS, 只不过要注意的就是如果检测的点的周围有mine, 不需要将neighbor 再append进入queue, 因为根据规则2 和3 可知不需要recursive去继续, 其他的就是常规的BFS的操作, 然后看了discussion之后, 发现可以将其中部分code简化为一行, python果然是简洁的语言!

 NOTE: if should be after the for loop.     sum([board[pr + d1][pc + d2] == 'M' for d1, d2 in dirs if 0 <= pr + d1 < lr and 0 <= pc + d2 < lc])

1. constraints

1) matrix [1,50] * [1, 50], cannot be empty

2) click will be 'M' or 'E', always valid

3) no 'X' at beginning.

 

2. ideas

BFS:   T: O(m*n)   S: O(m*n) # even we change in place, but we still need space for queue.

1, if click == 'M', change into "X" , return board

2. queue(init:[(orir, oric)]), visited(inti: set((orir, oric))), dirs

3. queue.popleft(), check neighbors , count number of 'M', if >0, change into str(count), else "B" and queue.append(neigb) if neigb == 'E' and not visited

4. return board

 

3. code 1 class Solution:

 2     def Mine(self, board, click):
 3         lr, lc , orir, oric = len(board), len(board[0]), click[0], click[-1]
 4         if board[orir][oric] == 'M': 
 5             board[orir][oric] = 'X'
 6             return board
 7         queue, visited, dirs = collections.deque([(orir, oric)]), set((orir, oric)), [(0,1), (0,-1), (-1,0), (-1,-1), (-1,1), (1, -1), (1,0), (1,1)]
 8         while queue:
 9             pr, pc = queue.popleft()
10             count = 0
11             # visited.add((pr,pc)) # 不在这里加是因为会time limit 不符合, 因为还是会有重复的加入情况, 因为不仅仅是上下左右,neib和之前的node只有一个connection, 现在有多个connection
12 for d1, d2 in dirs: 13 nr, nc = pr + d1, pc + d2 14 if 0<= nr < lr and 0<= nc < lc: 15 if board[nr][nc] == 'M': 16 count += 1 17 if count == 0: 18 board[pr][pc] = 'B' 19 for d1, d2 in dirs: 20 nr, nc = pr + d1, pc + d2 21 if 0<= nr < lr and 0<= nc < lc: 22 if board[nr][nc] == 'E' and (nr, nc) not in visited: 23 queue.append((nr, nc)) 24 visited.add((nr, nc)) # 所以visited加在这, 自行体会...
       count = 0  
25 return board

 

 

3.2  updated code(更简洁)

 1 lr, lc, orir, oric = len(board), len(board[0]), click[0], click[-1]
 2         if board[orir][oric] == 'M':
 3             board[orir][oric] = 'X'
 4             return board
 5         queue, visited, dirs = collections.deque([(orir,oric)]), set((orir, oric)), [(0,1), (0,-1), (-1,0), (-1,-1), (-1,1), (1, -1), (1,0), (1,1)]
 6         while queue:
 7             pr, pc = queue.popleft()
 8             #visited.add((pr,pc))
 9             count = sum(board[pr + d1][pc + d2] == 'M' for d1, d2 in dirs if 0 <= pr + d1 <lr and 0 <= pc + d2< lc)
10             board[pr][pc] = 'B' if count == 0 else str(count)
11             if count == 0:
12                 for d1, d2 in dirs:
13                     nr, nc = pr + d1, pc + d2
14                     if 0 <= nr <lr and 0 <= nc < lc and board[nr][nc] == 'E' and (nr, nc) not in visited:
15                         queue.append((nr,nc))
16                         visited.add((nr, nc))
17         return board

 

 3.3 DFS, 但是本质一样.

 1 # DFS   T: O(m*n)  S: O(m*n)   # only difference between DFS and BFS is one use stack , the other use deque. so to the 2D array if can use DFS, usually can use BFS too.
 2         lr, lc, orir, oric = len(board), len(board[0]), click[0], click[-1]
 3         if board[orir][oric] == 'M':
 4             board[orir][oric] = 'X'
 5             return board
 6         stack, visited, dirs = [(orir, oric)], set((orir, oric)), [(0,1), (0, -1), (1, -1), (1, 0), (1,1), (-1, -1), (-1, 0), (-1, 1)]
 7         while stack:
 8             pr, pc = stack.pop()
 9             count = sum(board[pr + d1][pc + d2]== 'M' for d1, d2 in dirs if 0<= pr+d1 < lr and 0<= pc + d2 < lc)
10             if count > 0:
11                 board[pr][pc] = str(count)
12             else:
13                 board[pr][pc] = 'B'
14                 for d1, d2 in dirs:
15                     nr, nc = pr + d1, pc + d2
16                     if 0 <= nr < lr and 0 <= nc < lc and board[nr][nc] == 'E' and (nr, nc) not in visited:
17                         stack.append((nr, nc))
18                         visited.add((nr, nc))
19         return board

 

4. test cases

题目上的两个cases