[Swift]LeetCode212. 單詞搜索 II | Word Search II

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

Given a 2D board and a list of words from the dictionary, find all words in the board.node

Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.git

Example:github

Input: 
words =  and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

Output: 
["oath","pea","eat","rain"]["eat","oath"]

Note:
You may assume that all inputs are consist of lowercase letters a-z.算法


給定一個二維網格 board 和一個字典中的單詞列表 words,找出全部同時在二維網格和字典中出現的單詞。微信

單詞必須按照字母順序,經過相鄰的單元格內的字母構成,其中「相鄰」單元格是那些水平相鄰或垂直相鄰的單元格。同一個單元格內的字母在一個單詞中不容許被重複使用。數據結構

示例:app

輸入: 
words =  and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

輸出: ["oath","pea","eat","rain"]["eat","oath"]

說明:
你能夠假設全部輸入都由小寫字母 a-z 組成。學習

提示:測試

    • 你須要優化回溯算法以經過更大數據量的測試。你可否早點中止回溯?
    • 若是當前單詞不存在於全部單詞的前綴中,則能夠當即中止回溯。什麼樣的數據結構能夠有效地執行這樣的操做?散列表是否可行?爲何? 前綴樹如何?若是你想學習如何實現一個基本的前綴樹,請先查看這個問題: 實現Trie(前綴樹)

328ms

  1 class TrieNode: CustomStringConvertible {
  2     var description: String {
  3         return "word:\(word)   children:\(children)"
  4     }
  5 
  6     var word: String? = nil
  7     var children = [Character:TrieNode]()
  8 }
  9 
 10 class TrieTree {
 11     let root = TrieNode()
 12 
 13     func insert(_ word:String) {
 14         var node: TrieNode? = root
 15         for c in word{
 16             guard let _node = node else {
 17                 continue
 18             }
 19             if let child = _node.children[c] {
 20                 node = child
 21             } else {
 22                 node = TrieNode()
 23                 _node.children[c] = node
 24             }
 25         }
 26         node?.word = word
 27 
 28         // print(root)
 29     }
 30 
 31     func hasPrefix(_ prefix:[Character]) -> Bool {
 32         var node: TrieNode? = root
 33         for c in prefix{
 34             guard let _node = node else {
 35                 return false
 36             }
 37             if let child = _node.children[c] {
 38                 node = child
 39             } else {
 40                 return false
 41             }
 42         }
 43         return true
 44     }
 45 
 46     func hasWord(_ word:[Character]) -> Bool {
 47         var node: TrieNode? = root
 48         for c in word{
 49             guard let _node = node else {
 50                 return false
 51             }
 52             if let child = _node.children[c] {
 53                 node = child
 54             } else {
 55                 return false
 56             }
 57         }
 58         return node?.word == nil ? false : true
 59     }
 60 }
 61 
 62 
 63 class Solution {
 64     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
 65         
 66         
 67         let trie = TrieTree()
 68         var record = [[Bool]](repeating:[Bool](repeating:false, count:board[0].count), count:board.count)
 69         var result = Set<String>()
 70         
 71         
 72         for word in words {
 73             trie.insert(word)
 74         }
 75         
 76         for x in 0..<board.count {
 77             for y in 0..<board[0].count {
 78                 guard let node = child(board,trie.root,x,y) else {
 79                     continue
 80                 }
 81                 search(board,&record,node,x,y, &result)
 82             }
 83         }
 84 
 85         return Array(result)
 86 
 87     }
 88     
 89     func child(_ board: [[Character]],_ node:TrieNode,_ x:Int,_ y:Int) -> TrieNode? {
 90         guard x < board.count, x >= 0, y < board[0].count, y >= 0 else {
 91             return nil
 92         }
 93         
 94         return node.children[board[x][y]]
 95     }
 96     
 97     func search (_ board: [[Character]],_ record:inout [[Bool]], _ node:TrieNode,_ x:Int, _ y:Int, _ result:inout Set<String>) {
 98         guard x < board.count, x >= 0, y < board[0].count, y >= 0, !record[x][y] else {
 99             return
100         }
101         
102         // print("\(x):\(y)    \(board[x][y])")
103         
104         if let word = node.word {
105             result.insert(word)
106         }
107         
108         record[x][y] = true
109         
110         if let nextNode = child(board,node,x+1,y) {
111             search(board,&record,nextNode,x+1,y, &result)
112         }
113         
114         if let nextNode = child(board,node,x-1,y) {
115             search(board,&record,nextNode,x-1,y, &result)
116         }
117         
118         if let nextNode = child(board,node,x,y+1) {
119             search(board,&record,nextNode,x,y+1, &result)
120         }
121         
122         if let nextNode = child(board,node,x,y-1) {
123             search(board,&record,nextNode,x,y-1, &result)
124         }
125         
126         record[x][y] = false
127     }
128 }

348ms

 1 class Solution {
 2     
 3     let lowerLetterUnicodeStart = Character("a").char2Int()
 4     
 5     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
 6         var board = board
 7         var result = [String]()
 8         let root = buildTrie(words)
 9         let (m, n) = (board.count, board[0].count)
10         
11         func dfs(_ i: Int, _ j: Int, _ root: TrieNode) {
12             if i < 0 || j < 0 || i >= m || j >= n { return }
13             let char = board[i][j]
14             let charIndex = char.char2Int() - lowerLetterUnicodeStart
15             if char == "#" || root.next[charIndex] == nil { return }
16             let root = root.next[charIndex]!
17             if let rootWord = root.word {
18                 result.append(rootWord)
19                 root.word = nil
20             }
21             board[i][j] = "#"
22             dfs(i - 1, j, root)
23             dfs(i, j - 1, root)
24             dfs(i + 1, j, root)
25             dfs(i, j + 1, root)
26             board[i][j] = char
27         }
28         
29         for i in 0..<m {
30             for j in 0..<n {
31                 dfs(i, j, root)
32             }
33         }
34         return result
35     }
36     
37     func buildTrie(_ words: [String]) -> TrieNode {
38         let root = TrieNode()
39         for word in words {
40             var point = root
41             for char in word {
42                 let charIndex = char.char2Int() - lowerLetterUnicodeStart
43                 if point.next[charIndex] == nil { point.next[charIndex] = TrieNode() }
44                 point = point.next[charIndex]!
45             }
46             point.word = word
47         }
48         return root
49     }
50 }
51 
52 class TrieNode {
53     var next: [TrieNode?] = Array(repeating: nil, count: 26)
54     var word: String?
55 }
56 
57 extension Character {
58     func char2Int() -> Int {
59         return Int(self.unicodeScalars.first!.value)
60     }
61 }

364ms

 1 class Solution {
 2     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
 3         var board = board
 4         var trie = Trie()
 5         
 6         for word in words {
 7             trie.insert(word)
 8         }
 9         
10         var result = [String]()
11         
12         if board.isEmpty {
13             return result
14         }
15         
16         for i in 0 ..< board.count {
17             for j in 0 ..< board[0].count {
18                 dfs(&board, i, j, trie.root, &result)
19             }
20         }
21         return result
22     }
23     
24     func dfs(_ board: inout [[Character]], _ i: Int, _ j: Int, _ trie: TrieNode, _ result: inout [String]) {
25         var trie = trie
26         
27         if board[i][j] == "*" || trie.children[board[i][j]] == nil {
28             return
29         }
30         
31         trie = trie.children[board[i][j]]!
32         
33         if trie.word != "*" {
34             result.append(trie.word)
35             trie.word = "*"
36         }
37         
38         var cur = board[i][j]
39         board[i][j] = "*"
40         if (i < board.count-1) { dfs(&board, i+1, j, trie, &result) }
41         if (i > 0) { dfs(&board, i-1, j, trie, &result) }
42         if (j < board[0].count-1) { dfs(&board, i, j+1, trie, &result) }
43         if (j > 0) { dfs(&board, i, j-1, trie, &result) }
44         board[i][j] = cur
45         return
46     }
47 }
48 
49 class Trie {
50     public var root = TrieNode()
51     
52     public func insert(_ word: String) {
53         var head = root
54         
55         for w in word {
56             if head.children[w] == nil {
57                 head.children[w] = TrieNode()
58             }
59             
60             head = head.children[w]!
61         }
62         head.word = word
63     }
64 }
65 
66 class TrieNode {
67     public var word: String = "*"
68     public var children = [Character : TrieNode]()
69 }

384ms

 1 class TrieNode {
 2     var word: String? = nil
 3     var children = [Character:TrieNode]()
 4 }
 5 
 6 class TrieTree {
 7     let root = TrieNode()
 8 
 9     func insert(_ word:String) {
10         var node: TrieNode? = root
11         for c in word{
12             guard let _node = node else {
13                 continue
14             }
15             if let child = _node.children[c] {
16                 node = child
17             } else {
18                 node = TrieNode()
19                 _node.children[c] = node
20             }
21         }
22         node?.word = word
23     }
24 }
25 
26 
27 class Solution {
28     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
29         
30         
31         let trie = TrieTree()
32         var record = [[Bool]](repeating:[Bool](repeating:false, count:board[0].count), count:board.count)
33         var result = Set<String>()
34         
35         
36         for word in words {
37             trie.insert(word)
38         }
39         
40         for x in 0..<board.count {
41             for y in 0..<board[0].count {
42                 guard let node = trie.root.children[board[x][y]] else {
43                     continue
44                 }
45                 search(board,&record,node,x,y, &result)
46             }
47         }
48 
49         return Array(result)
50 
51     }
52     
53     
54     func search (_ board: [[Character]],_ record:inout [[Bool]], _ node:TrieNode,_ x:Int, _ y:Int, _ result:inout Set<String>) {
55         guard !record[x][y] else {
56             return
57         }
58 
59         if let word = node.word {
60             result.insert(word)
61         }
62         
63         record[x][y] = true
64         
65         for (x,y) in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)] {
66             guard x < board.count, x >= 0, y < board[0].count, y >= 0, let next = node.children[board[x][y]] else {
67                 continue
68             }
69             search(board,&record,next,x,y, &result)
70         }
71         
72         record[x][y] = false
73     }
74 }

488ms

 1 class Solution {
 2     let directions = [
 3         [0, 1],
 4         [1, 0],
 5         [0, -1],
 6         [-1, 0],
 7     ]
 8     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
 9         var result = [String]() 
10         guard board.count > 0 && board[0].count > 0 && words.count > 0 else {
11             return result
12         }
13         var wordChars = words.map { Array($0) }
14         var root = TrieNode()
15         for chars in wordChars {
16             buildTree(&root, chars)   
17         }
18         var board = board
19         for row in 0..<board.count {
20             for col in 0..<board[0].count {
21                 doFindWords(&board, &result, row, col, &root)
22             }
23         }
24         return result
25     }
26     
27     private func doFindWords(_ board: inout [[Character]], _ result: inout [String], _ row: Int, _ col: Int, _ node: inout TrieNode) {
28         guard 0 <= row && row < board.count && 0 <= col && col < board[0].count else {
29             return
30         }
31         let char = board[row][col]
32         guard node.next[char] != nil else {
33             return
34         }
35         var node = node.next[char]!
36         if let word = node.getWord() {
37             result.append(word)
38             node.setWord(nil)
39         }
40         board[row][col] = "#"
41         for direction in directions {
42             doFindWords(&board, &result, row + direction[0], col + direction[1], &node)
43         }
44         board[row][col] = char
45     }
46     
47     private func buildTree(_ root: inout TrieNode, _ chars: [Character]) {
48         var node = root
49         for char in chars {
50             if node.next[char] == nil {
51                 node.next[char] = TrieNode()
52             }
53             node = node.next[char]!
54         }
55         node.setWord(String(chars))
56     }
57 }
58 
59 class TrieNode {
60     var next: [Character: TrieNode]
61     var word: String?
62     
63     init() {
64         self.next = [Character: TrieNode]()
65         self.word = nil
66     }
67     
68     func setWord(_ word: String?) {
69         self.word = word
70     }
71     
72     func getWord() -> String? {
73         return word
74     }
75 }

500ms

 1 class Solution {
 2     private class TrieNode {
 3         var children: [TrieNode?]
 4         var word: String?
 5         
 6         init() {
 7             children = [TrieNode?](repeating: nil, count: 26)
 8             word = nil
 9         }
10     }
11     
12     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
13         var result = [String]()
14         let trieRoot = buildTrie(from: words)
15         let rows = board.count, cols = board[0].count
16         let rowSeen = [Bool](repeating: false, count: cols)
17         var seen = [[Bool]](repeating: rowSeen, count: rows)
18         for r in 0..<rows {
19             for c in 0..<cols {
20                 result.append(contentsOf: search(board, &seen, r, c, trieRoot))
21             }
22         }
23         return result
24     }
25     
26     private func buildTrie(from words: [String]) -> TrieNode {
27         let root = TrieNode()
28         for word in words {
29             var node: TrieNode? = root
30             for char in word.unicodeScalars {
31                 let index = Int(char.value) - 97
32                 if node?.children[index] == nil {
33                     node?.children[index] = TrieNode()
34                 }
35                 node = node?.children[index]
36             }
37             node?.word = word
38         }
39         return root
40     }
41     
42     private func search(_ board: [[Character]], _ seen: inout [[Bool]], _ r: Int, _ c: Int, _ node: TrieNode) -> [String] {
43         guard 0 <= r && r < board.count && 0 <= c && c < board[0].count && !seen[r][c] else {
44             return []
45         }
46         let childNodeIndex = Int(board[r][c].unicodeScalars.first!.value) - 97
47         guard let childNode = node.children[childNodeIndex] else {
48             return []
49         }
50         var result = [String]()
51         if let word = childNode.word {
52             result.append(word)
53             childNode.word = nil
54         }
55         seen[r][c] = true
56         result.append(contentsOf: search(board, &seen, r + 1, c, childNode))
57         result.append(contentsOf: search(board, &seen, r - 1, c, childNode))
58         result.append(contentsOf: search(board, &seen, r, c + 1, childNode))
59         result.append(contentsOf: search(board, &seen, r, c - 1, childNode))
60         seen[r][c] = false
61         return result
62     }
63 }

524ms

 1 class Solution {
 2     
 3     class WordNode {
 4         var children = [WordNode]()
 5         var isWord = false
 6         var char : Character
 7         init(_ c : Character) {
 8             char = c
 9         }
10     }
11     
12     func addWord(_ word : String, _ node : WordNode){
13         var lastNode = node
14         let wordArr = Array(word)
15         for c in wordArr {
16             var find = false
17             for sub in lastNode.children where sub.char == c {
18                 find = true
19                 lastNode = sub
20             }
21             
22             if !find {
23                 let nc = WordNode(c)
24                 lastNode.children.append(nc)
25                 lastNode = nc
26             }
27         }
28         lastNode.isWord = true
29     }
30     
31     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
32         
33         let root = WordNode(".")
34         
35         for word in words {
36             addWord(word, root)
37         }
38         
39         var curr = ""
40         var res = Set<String>()
41         var visited = Array(repeating: Array(repeating: false, count: board[0].count), count: board.count)
42         for i in 0..<board.count {
43             for j in 0..<board[0].count {
44                 find(board, &visited, i, j, root, &res, &curr)
45             }
46         }
47         
48         return Array(res)
49     }
50     
51     func find(_ board : [[Character]], _ visited : inout [[Bool]], _ m : Int, _ n : Int ,_ node : WordNode, _ res : inout Set<String>, _ curr : inout String) {
52 
53         
54 
55         
56         let c = board[m][n]
57         var sub : WordNode?
58         for child in node.children where child.char == c {
59             sub = child
60             curr += String(sub!.char)
61         }
62         if sub == nil {
63             return
64         }
65         
66         
67         if sub!.isWord {
68             res.insert(curr)
69         }
70         
71         visited[m][n] = true
72         if m+1 < board.count && !visited[m+1][n] {
73             find(board, &visited, m+1, n, sub!, &res, &curr)
74         }
75         if n+1 < board[0].count && !visited[m][n+1] {
76             find(board, &visited, m, n+1, sub!, &res, &curr)
77         }
78         if m > 0 && !visited[m-1][n] {
79             find(board, &visited, m-1, n, sub!, &res, &curr)
80         }
81         if n > 0 && !visited[m][n-1] {
82             find(board, &visited, m, n-1, sub!, &res, &curr)
83         }
84         visited[m][n] = false
85         curr.popLast()
86     }
87 }

548ms

  1 class Node: CustomStringConvertible  {
  2     var index: Int
  3     var char: Character
  4     var children = [Node]()
  5     
  6     public var description: String { return "Node: \(index) -> \(char) & \(children.count)" }
  7     
  8     init(_ i: Int, _ c: Character) {
  9         index = i
 10         char = c
 11     }
 12 }
 13 
 14 extension String {
 15     func charAt(_ i: Int) -> Character {
 16         return self[index(startIndex, offsetBy: i)]
 17     }
 18 }
 19 
 20 class Solution {
 21     let abc = (97...122).map({Character(UnicodeScalar($0))})
 22     
 23     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
 24         
 25         var ans = Set<String>()
 26         var m = board.count
 27         var n = board[0].count
 28         var root = [[Node]]()
 29         
 30         for i in 0..<m {
 31             root.append([Node]())
 32             for j in 0..<n {
 33                 root[i].append(Node((i * n) + j, board[i][j]))
 34             }
 35         }
 36         
 37         for i in 0..<m {
 38             for j in 0..<n {
 39                 if i > 0 {
 40                     root[i][j].children.append(root[i - 1][j])
 41                 }
 42                 if i < m - 1 {
 43                     root[i][j].children.append(root[i + 1][j])
 44                 }
 45                 if j > 0 {
 46                     root[i][j].children.append(root[i][j - 1])
 47                 }
 48                 if j < n - 1 {
 49                     root[i][j].children.append(root[i][j + 1])
 50                 }
 51             }
 52         }
 53         
 54         // print(root)
 55         
 56         for word in words {
 57             var visited = [Bool](repeating: false, count: m * n)
 58             var index = 0
 59             
 60             if (search(root, &visited, String(word.reversed()), &index)) {
 61                 ans.insert(word)
 62             }
 63         }
 64         
 65         return Array(ans)
 66     }
 67     
 68     func search(_ root: [[Node]], _ visited: inout [Bool], _ word: String, _ index: inout Int) -> Bool {
 69         if index == word.count {
 70             return true
 71         }
 72         
 73         let charToFind = word.charAt(index)
 74         var validNodes = [Node]()
 75         
 76         for row in root {
 77             for node in row {
 78                 if node.char == charToFind {
 79                     if !visited[node.index] {
 80                         validNodes.append(node)
 81                     }
 82                 }
 83             }
 84         }
 85         
 86         // print(validNodes)
 87         
 88         for node in validNodes {
 89             visited[node.index] = true
 90             index += 1
 91             if searchInWord(node, &visited, word, &index) {
 92                 return true
 93             }
 94             index -= 1
 95             visited[node.index] = false
 96         }
 97         
 98         return false
 99     }
100     
101     func searchInWord(_ root: Node, _ visited: inout [Bool], _ word: String, _ index: inout Int) -> Bool {
102         if index == word.count {
103             return true
104         }
105         
106         let charToFind = word.charAt(index)
107         var validNodes = [Node]()
108         
109         for node in root.children {
110             if node.char == charToFind && !visited[node.index] {
111                 validNodes.append(node)
112             }
113         }
114         
115         for node in validNodes {
116             visited[node.index] = true
117             index += 1
118             if searchInWord(node, &visited, word, &index) {
119                 return true
120             }
121             index -= 1
122             visited[node.index] = false
123         }
124         
125         return false
126     }
127 }

684ms

 1 class Solution {
 2     func findWords(_ board: [[Character]], _ words: [String]) -> [String] {
 3         //check if board or word is empty
 4         if board.count == 0 || board[0].count == 0 || words.count == 0 {
 5             return []
 6         }   
 7         var rowCount = board.count
 8         var colCount = board[0].count
 9         
10         //convert word to a prefix map
11         var isWordMap: [String: Bool] = getWordMap(words)
12         
13         //2D array to track visited location
14         var visited = Array(repeating: Array(repeating: false, count: colCount), count: rowCount)
15         
16         //result: use set to remove duplicate 
17         var wordSet: Set<String> = Set<String>()
18         
19         for i in 0 ..< rowCount {
20             for j in 0 ..< colCount {
21                 visited[i][j] = true
22                 //use word map to find words that be constrcuted from letters
23                 findWord(i, j, String(board[i][j]), isWordMap, &visited, &wordSet, board)
24                 visited[i][j] = false
25             }
26         }
27         return Array(wordSet)
28     }
29     
30     private func getWordMap(_ words: [String]) -> [String: Bool] {
31         var wordMap = [String: Bool]() 
32         for word in words {
33             for i in 1 ... word.count {
34                 let subString = String(word.prefix(i))
35                 if wordMap[subString] == nil {
36                     wordMap[subString] = false
37                 }
38             }
39             wordMap[word] = true
40         }
41         return wordMap
42     }
43     
44     private func findWord(_ colIndex: Int, _ rowIndex: Int, 
45                     _ word: String, _ wordMap: [String: Bool],
46                     _ visited: inout [[Bool]], _ res: inout Set<String>,
47                     _ charBoard: [[Character]]) {
48         //wordMap doesn't contain the prefix, exit
49         if wordMap[word] == nil {
50             return
51         }
52         
53         //prefix is word, add to result
54         if wordMap[word]! {
55             res.insert(word)
56         }
57         
58         //4 directions
59         let dirX = [0, 0, 1, -1]
60         let dirY = [1, -1, 0, 0]
61         
62         for i in 0 ..< 4 {
63             let newCol = colIndex + dirX[i]
64             let newRow = rowIndex + dirY[i]
65             
66             //check bounds and if it is visited
67             if !inDict(newCol, newRow, charBoard.count, charBoard[0].count) || visited[newCol][newRow] {
68                 continue
69             }
70             
71             visited[newCol][newRow] = true
72             //keep checking if word map contains new string
73             findWord(newCol, newRow, word + String(charBoard[newCol][newRow]),
74                     wordMap, &visited, &res, charBoard)
75             visited[newCol][newRow] = false
76         }
77     }
78     
79     private func inDict(_ colIndex: Int, _ rowIndex: Int, _ colMax: Int, _ rowMax: Int) -> Bool {
80         return colIndex >= 0 && rowIndex >= 0 && colIndex < colMax && rowIndex < rowMax
81     }
82 }
相關文章
相關標籤/搜索