[Swift]LeetCode529. 掃雷遊戲 | Minesweeper

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公衆號:山青詠芝(shanqingyongzhi)
➤博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:http://www.javashuo.com/article/p-vxwjtvzh-me.html 
➤若是連接不是山青詠芝的博客園地址,則多是爬取做者的文章。
➤原文已修改更新!強烈建議點擊原文地址閱讀!支持做者!支持原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★html

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

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.github

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

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:ide

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:this

  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.

讓咱們一塊兒來玩掃雷遊戲!spa

給定一個表明遊戲板的二維字符矩陣。 'M' 表明一個未挖出的地雷,'E' 表明一個未挖出的空方塊,'B' 表明沒有相鄰(上,下,左,右,和全部4個對角線)地雷的已挖出的空白方塊,數字('1' 到 '8')表示有多少地雷與這塊已挖出的方塊相鄰,'X' 則表示一個已挖出的地雷。code

如今給出在全部未挖出的方塊中('M'或者'E')的下一個點擊位置(行和列索引),根據如下規則,返回相應位置被點擊後對應的面板:orm

  1. 若是一個地雷('M')被挖出,遊戲就結束了- 把它改成 'X'。
  2. 若是一個沒有相鄰地雷的空方塊('E')被挖出,修改它爲('B'),而且全部和其相鄰的方塊都應該被遞歸地揭露。
  3. 若是一個至少與一個地雷相鄰的空方塊('E')被挖出,修改它爲數字('1'到'8'),表示相鄰地雷的數量。
  4. 若是在這次點擊中,若無更多方塊可被揭露,則返回面板。 

示例 1:

輸入: 

[['E', 'E', 'E', 'E', 'E'],
 ['E', 'E', 'M', 'E', 'E'],
 ['E', 'E', 'E', 'E', 'E'],
 ['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

輸出: 

[['B', '1', 'E', '1', 'B'],
 ['B', '1', 'M', '1', 'B'],
 ['B', '1', '1', '1', 'B'],
 ['B', 'B', 'B', 'B', 'B']]

解釋:

示例 2:

輸入: 

[['B', '1', 'E', '1', 'B'],
 ['B', '1', 'M', '1', 'B'],
 ['B', '1', '1', '1', 'B'],
 ['B', 'B', 'B', 'B', 'B']]

Click : [1,2]

輸出: 

[['B', '1', 'E', '1', 'B'],
 ['B', '1', 'X', '1', 'B'],
 ['B', '1', '1', '1', 'B'],
 ['B', 'B', 'B', 'B', 'B']]

解釋:

注意:

  1. 輸入矩陣的寬和高的範圍爲 [1,50]。
  2. 點擊的位置只能是未被挖出的方塊 ('M' 或者 'E'),這也意味着面板至少包含一個可點擊的方塊。
  3. 輸入面板不會是遊戲結束的狀態(即有地雷已被挖出)。
  4. 簡單起見,未說起的規則在這個問題中可被忽略。例如,當遊戲結束時你不須要挖出全部地雷,考慮全部你可能贏得遊戲或標記方塊的狀況。

388ms

 1 class Solution {
 2       func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
 3           var board = board
 4           return coreUpdateBoard(&board, click)
 5       }
 6     func coreUpdateBoard(_ board: inout [[Character]], _ click: [Int]) -> [[Character]] {
 7         let m = board.count, n = board[0].count
 8         let row = click[0], col = click[1]
 9 
10         if board[row][col] == "M" {
11             board[row][col] = "X"
12         }
13         else { // Empty
14             // Get number of mines first.
15             var count = 0
16             for i in -1..<2 {
17                 for j in -1..<2 {
18                     if i == 0 && j == 0 {
19                         continue
20                     }
21                     let r = row + i, c = col+j
22                     if r<0 || r>=m || c<0 || c>=n {
23                         continue
24                     }
25 
26                     if board[r][c] == "M" || board[r][c] == "X" {
27                         count += 1
28                     }
29                 }
30             }
31 
32             if count > 0 { 
33                 // If it is not a 'B', stop further DFS.
34                 board[row][col] = Character("\(count)")
35             }
36             else {
37                 // Continue DFS to adjacent cells.
38                 board[row][col] = "B"
39                 for i in -1..<2 {
40                     for j in -1..<2 {
41                         if i == 0 && j == 0 {
42                             continue
43                         }
44                         let r = row+i, c = col + j
45                         if r<0 || r>=m || c<0 || c>=n {
46                             continue
47                         }
48                         if board[r][c] == "E" {
49                             coreUpdateBoard(&board, [r,c])
50                         }
51                     }
52                 }
53             }
54         }
55         return board
56     }
57 }

392ms

 1 class Solution {
 2     let dirs: [(Int, Int)] = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
 3     
 4     func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
 5         var board: [[Character]] = board
 6         let x = click[0]
 7         let y = click[1]
 8         if board[x][y] == "M" {
 9             board[x][y] = "X"
10             return board
11         }
12         dfs(&board, x, y)
13         return board
14     }
15     
16     func dfs(_ board: inout [[Character]], _ x: Int, _ y: Int) {
17         if x < 0 || x >= board.count || y < 0 || y >= board[0].count || board[x][y] != "E" {
18             return 
19         }
20         let mineCount = numberOfMines(&board, x, y)
21         if mineCount == 0 {
22             board[x][y] = "B"
23             for d in dirs {
24                 dfs(&board, x + d.0, y + d.1)
25             }
26         } else {
27             board[x][y] = Character(String(mineCount))
28         }
29     }
30     
31     func numberOfMines(_ board: inout [[Character]], _ x: Int, _ y: Int) -> Int {
32         var count = 0
33         for d in dirs {
34             let newX = x + d.0
35             let newY = y + d.1
36             if newX < 0 || newX >= board.count || newY < 0 || newY >= board[0].count {
37                 continue
38             }
39             if board[newX][newY] == "M" || board[newX][newY] == "X" {
40                 count += 1
41             }
42         }
43         return count
44     }
45 }

Runtime: 396 ms
Memory Usage: 20.4 MB
 1 class Solution {
 2     func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
 3         if board.isEmpty || board[0].isEmpty {return []}
 4         var board = board
 5         var m:Int = board.count
 6         var n:Int = board[0].count
 7         var q:[[Int]] = [[click[0], click[1]]]
 8         while(!q.isEmpty)
 9         {
10             var row:Int = q.first![0]
11             var col:Int = q.first![1]
12             var cnt:Int = 0
13             q.removeFirst()
14             var neighbors:[[Int]] = [[Int]]()
15             if board[row][col] == "M"
16             {
17                 board[row][col] = "X"
18             }
19             else
20             {
21                 for i in -1..<2
22                 {
23                     for j in -1..<2
24                     {
25                         var x:Int = row + i
26                         var y:Int = col + j
27                         if x < 0 || x >= m || y < 0 || y >= n
28                         {
29                             continue
30                         }
31                         if board[x][y] == "M"
32                         {
33                             cnt += 1
34                         }
35                         else if cnt == 0 && board[x][y] == "E"
36                         {
37                             neighbors.append([x, y])
38                         }
39                     }
40                 }
41             }
42             if cnt > 0 
43             {
44                 board[row][col] = (cnt + 48).ASCII
45             }
46             else
47             {
48                 for a in neighbors
49                 {
50                     board[a[0]][a[1]] = "B"
51                     q.append(a)
52                 }
53             }
54         }
55         return board
56     }
57 }
58 
59 extension Int
60 {
61     //屬性:ASCII值(定義大寫爲字符值)
62     var ASCII:Character 
63     {
64         get {return Character(UnicodeScalar(self)!)}
65     }
66 }

412ms

 1 class Solution {
 2     func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] {
 3       let rows = board.count, cols = board[0].count
 4       var currentTuple: (Int, Int) = (click[0], click[1])
 5       var board = board
 6     
 7       var queue = [currentTuple]
 8 
 9       while !queue.isEmpty {
10         let (currX, currY) = queue.popLast()!
11 
12         if board[currX][currY] == "M" {
13           board[currX][currY] = "X" // Game over!
14         } else {
15 
16           // Get total number of mines surrounding the square
17           var count = 0
18 
19           for (dx, dy) in [(1, 0), (0, 1), (-1, 0), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)] {
20             let (nextX, nextY) = (dx + currX, dy + currY)
21             if nextX >= 0 && nextX < rows && nextY >= 0 && nextY < cols {
22               if ["M", "X"].contains(board[nextX][nextY]) {
23                 count += 1
24               }
25             }
26           }
27 
28           if count > 0 {
29             // Terminate search
30             board[currX][currY] = Character.init("\(count)")
31           } else {
32             // Else, perform BFS search
33             board[currX][currY] = "B"
34 
35             for (dx, dy) in [(1, 0), (0, 1), (-1, 0), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)] {
36               let (nextX, nextY) = (dx + currX, dy + currY)
37               if nextX >= 0 && nextX < rows && nextY >= 0 && nextY < cols {
38                 if ["E"].contains(board[nextX][nextY]) {
39                   queue.append((nextX, nextY))
40                   board[nextX][nextY] = "B"
41                 }
42               }
43             }
44           } 
45         } 
46       }
47       return board
48    }
49 }

628ms

 1         reveal(board: &board, i:click[0], j:click[1])
 2         return board
 3         
 4     }
 5     
 6     func reveal(board: inout [[Character]], i:Int, j:Int) {
 7         switch (String(board[i][j])) {
 8             case "M":
 9                 board[i][j] = Character("X")
10                 break
11             case "E":
12             if (adjacencies[i][j] == 0) {
13                 board[i][j] = Character("B")
14                 directions.forEach { dir in
15             let (y, x) = dir
16             if isValid(i:y + i, j: x + j)  {
17                 reveal(board: &board, i: y + i, j:x + j)
18             }
19         }
20                 break
21             } else {
22                 
23                 board[i][j] = Character(String(adjacencies[i][j]))
24             }
25                 
26             default:
27             break
28         }
29     }
30     
31     func setAdjacency(_ board: [[Character]], i: Int, j: Int) {
32         var adjacency = 0
33         directions.forEach { dir in
34             let (y, x) = dir
35             if isValid(i:y + i, j: x + j) && board[y + i][x + j] == "M" {
36                 adjacency += 1
37             }
38         }
39         adjacencies[i][j] = adjacency
40           
41     }
42     
43     func isValid(i:Int, j:Int) -> Bool {
44         return i < m && i >= 0 && j >= 0 && j < n 
45     }
46 }
相關文章
相關標籤/搜索