如何解决了解Word Search 2 Leetode的图形解决方案 示例
class Solution:
def findWords(self,board: List[List[str]],words: List[str]) -> List[str]:
WORD_KEY = '$'
trie = {}
for word in words:
node = trie
for letter in word:
# retrieve the next node; If not found,create a empty node.
node = node.setdefault(letter,{})
# mark the existence of a word in trie node
node[WORD_KEY] = word
rowNum = len(board)
colNum = len(board[0])
matchedWords = []
def backtracking(row,col,parent):
letter = board[row][col]
currNode = parent[letter]
# check if we find a match of word
word_match = currNode.pop(WORD_KEY,False)
if word_match:
# also we removed the matched word to avoid duplicates,# as well as avoiding using set() for results.
matchedWords.append(word_match)
# Before the EXPLORATION,mark the cell as visited
board[row][col] = '#'
# Explore the neighbors in 4 directions,i.e. up,right,down,left
for (rowOffset,colOffset) in [(-1,0),(0,1),(1,-1)]:
newRow,newCol = row + rowOffset,col + colOffset
if newRow < 0 or newRow >= rowNum or newCol < 0 or newCol >= colNum:
continue
if not board[newRow][newCol] in currNode:
continue
backtracking(newRow,newCol,currNode)
# End of EXPLORATION,we restore the cell
board[row][col] = letter
# Optimization: incrementally remove the matched leaf node in Trie.
if not currNode:
parent.pop(letter)
for row in range(rowNum):
for col in range(colNum):
# starting from each of the cells
if board[row][col] in trie:
backtracking(row,trie)
return matchedWords
我不知道特里如何存储数据结构。来自摘要:
for word in words:
node = trie
for letter in word:
# retrieve the next node; If not found,create a empty node.
node = node.setdefault(letter,{})
# mark the existence of a word in trie node
node[WORD_KEY] = word
节点应该存储数据结构(例如{o:{a:{t:{h:{$:'oath'}}}}}}等),而不是trie。但是,当我调试代码时,我看到此数据结构同时存储在节点和trie中。
解决方法
trie
是根节点,它只需获取一次值,此后就不再需要更改。因此,在代码开始时,您需要对trie
进行以下初始化:
trie = {}
另一方面,变量node
是一种指针,它遍历Trie中的现有节点以检查其中的字母。它总是开始指向根,所以我们有:
node = trie
然后在循环中更深入地进入Trie,或者跟随现有的子节点,或者如果不存在则创建一个新的子节点。所有这一切都发生在这一声明中:
node = node.setdefault(letter,{})
这是以下三个语句的缩写:
if letter not in node: # property letter does not yet exist here...
node[letter] = {} # create it,and attach a new node to it,extending trie
node = node[letter] # move the pointer to that new node
当node
遍历树状结构,有时将现有节点扩展为新的子节点时,我们实际上是在trie
内(深处)进行突变。这对于嵌套对象结构是典型的:您可以使这些对象更加嵌套,而不必直接将任何东西分配给具有顶级对象的变量。
示例
让我们说一个单词只添加了一个单词; “酒吧”一词。这是发生了什么:
首先执行tree = {}
。
外循环遍历单词。由于我们只有一个,因此将只有一个迭代。
然后执行node = tree
。因此,我们现在有两个对同一个空字典的引用:
{} # this is: trie,and also: node
内部循环重复三次。第一个letter
是“ b”。
setdefault
检测到node
没有属性“ b”,因此创建它。这会使node
突变,现在从{}
变为{ "b": {} }
。意识到此时node
和trie
引用了 same 词典,所以trie
也是这样:
{ # this is: trie,also: node
"b": {}
}
然后,在同一语句中,node
被分配了此新属性“ b”的值,即{}
。现在trie
和node
不再是相同的引用:
{ # this is: trie
"b": {} # this is: node
}
我们转到下一个迭代。现在letter
是“ a”。同样,setdefault
检测到node
没有“ a”属性(它是一个空字典),因此该属性是用一个新的空字典作为值来创建的。我们遇到这种情况
{ # this is: trie
"b": { # this is: node
"a": {}
}
}
再次在同一条语句中,为node
分配新创建的字典:
{ # this is: trie
"b": {
"a": {} # this is: node
}
}
类似地,相同的过程在第三次迭代中添加“ r”:
{ # this is: trie
"b": {
"a": {
"r": {} # this is: node
}
}
}
循环后,执行以下语句:
node[WORD_KEY] = word
因此,深层词典也具有一个属性:
{ # this is: trie
"b": {
"a": {
"r": { # this is: node
"$": "bar"
}
}
}
}
因此,您将看到此过程如何扩展原始trie
词典。与开始时一样,它仍然是同一本词典,但是它刚刚收到了一个属性,并带有一个词典作为值,而该属性又得到了扩展。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。