我有一个与Trie相关的想法,复杂度为O(N):
首先,你从空的Trie开始。
接下来,你逐个添加单词到Trie中。
当你添加一个单词(我们暂且称之为Wi)到Trie中后,有两种情况需要考虑:
- Wi是之前添加的某些单词的前缀。如果在添加单词Wi时没有向Trie中添加任何节点,则该语句为真。在这种情况下,Wi是前缀并且是我们解决方案的一部分。
- 之前添加的某些单词是Wi的前缀。如果你经过了代表之前添加的某个单词Wj的节点的末尾,则该语句为真。在这种情况下,Wj是Wi的前缀,并且是我们解决方案的一部分。
更详细地说(伪代码):
for word in words
add word to trie
if size of trie did not change then // first case
add word to result
if ending nodes found while adding word // second case
add words defined by those nodes to result
return result
向Trie树中添加新词:
node = trie.root();
for letter in word
if node.hasChild(letter) == false then // if letter doesnt exist, add it
node.addChild(letter)
if letter is last_letter_of_word then // if last letter of word, store that info
node.setIsLastLetterOf(word)
node = node.getChild(letter) // move
在您添加新单词的同时,您还可以检查是否通过了表示其他单词结尾字母的任何节点。我所描述的算法的复杂度为O(N)。另一个重要的事情是,通过这种方式,您可以知道单词Wi前缀其他单词的次数,这可能会很有用。
以下是{aab、aaba、aa}的示例:绿色节点是作为情况1检测到的节点。红色节点是作为情况2检测到的节点。每个列(trie)是一步。在开始时,trie为空。黑色箭头显示我们在该步骤中访问(添加)的节点。表示某些单词的最后一个字母的节点将该单词写在括号中。
在步骤1中,我们添加了单词aab。
在步骤2中,我们添加了单词aaba,识别出一种情况2(单词aab),并将单词aab添加到结果中。
在第3步中,我们添加了单词aa,识别出情况1,并将单词aa添加到结果中。
最后,我们得到了结果={aab、aa},这是正确的。