我正在处理一个问题,我需要检查字典中可以组合多少单词以匹配单个单词。
例如:
鉴于字符串" hellogoodsir "和字典:{hello,good,sir,go,od,e,l},目标是找到所有可能的组合形成字符串。
在这种情况下,结果将是 hello + good + sir , hello + go + od + sir ,导致使用3 + 4 = 7个单词,或1 + 1 = 2种组合。
我所提出的只是将所有单词以第一个字符开头(" h"在此实例中)放在一个散列图(startH)中,其余的放在另一个散列映射中(endH)。然后我查看startH hashmap中的每个单词,并检查" hellogoodsir"包含新单词(开始+结束),其中end是endH hashmap中的每个单词。如果是,我检查它是否等于要匹配的单词,然后使用每个单词的数字值递增计数器。如果它包含它,但不等于它,我使用新单词(即start + end)调用相同的方法(递归),并继续尝试将结束hashmap中的任何单词追加到新单词to to得到一个匹配。
对于大量单词(以及要匹配的长字符串),这显然非常慢。有没有更有效的方法来解决这个问题?
据我所知,这是一个O(n ^ 2)算法,但我确信这可以更快地完成。
答案 0 :(得分:0)
让我们从您的解决方案开始。它不是线性也不是二次时间,它实际上是指数时间。一个反例显示:
word = "aaa...a"
dictionary = {"a", "aa", "aaa", ..., "aa...a"}
由于您的解决方案正在经历每个可能的匹配,并且在此示例中存在指数数量 - 解决方案是指数时间。
然而,通过遵循递归公式,可以更有效地完成(二次时间最坏情况)Dynamic Programming:
D[0] = 1 #
D[i] = sum { D[j] | word.Substring(i,j) is in the dictionary | 0 <= j < i }
在D[i]
中完成计算每个O(i)
(先前已知的)
这总计为O(n^2)
时间,O(n)
额外空格。
快速注释:通过为每个(i,j)
迭代字典而不是所有D[i]
对,您可以为每个D [i]实现O(k)时间,最终为O(n*k)
,其中k
是字典大小。这可以通过仅遍历可能有效的字符串来优化某些情况 - 但对于与上面相同的计数器示例,它将导致O(n*k)
。
示例:强>
dictionary = {hello, good, sir, go, od, e, l}
string = "hellogoodsir"
D[0] = 1
D[1] = 0 (no substring h)
D[2] = 0 (no substring he, d[1] = 0 for e)
...
D[5] = 1 (hello is the only valid string in dictionary)
D[6] = 0 (no dictionary string ending with g)
D[7] = D[5], because string.substring(5,7)="go" is in dictionary
D[8] = 0, no substring ending with "oo"
D[9] = 2: D[7] for "od", and D[5] for "good"
D[10] = D[11] = 0 (no strings in dictionary ending with "si" or "s")
D[12] = D[7] = 2 for substring "sir"
答案 1 :(得分:0)
我的建议是使用prefix tree。根目录下的节点可以是h
,g
,s
,o
,e
和l
。您还需要节点来终止字符,以区分go
和good
。
要查找所有匹配项,请使用广度优先搜索方法。您要跟踪的状态是以下内容的组合:搜索字符串中的当前索引,树中的当前节点以及到目前为止使用的单词列表。
初始状态应为0,root,[]
当状态列表不为空时,将下一个状态出列,并查看索引是否与节点子节点的任何键匹配。如果是这样,请修改状态的副本并将其排入队列。此外,如果任何子节点是终止字符,请执行相同的操作,将该单词添加到状态中的列表中。
我不确定此算法的O(n)时间,但它应该快得多。