为有牺牲多壮志,敢教日月换新天。

[Swift]LeetCode212. 单词搜索 II | Word Search II

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10197862.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

热烈欢迎,请直接点击!!!

进入博主App Store主页,下载使用各个作品!!!

注:博主将坚持每月上线一个新app!!!

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

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.

Example:

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

Output: ["eat","oath"]

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


给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例:

输入: 
words = ["oath","pea","eat","rain"] and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

输出: ["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 }

 

posted @ 2018-12-29 20:39  为敢技术  阅读(413)  评论(0编辑  收藏  举报