将字典中的单词组合以匹配单个单词

时间:2017-05-10 18:45:57

标签: string algorithm dictionary

我正在处理一个问题,我需要检查字典中可以组合多少单词以匹配单个单词。

例如:
鉴于字符串" 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)算法,但我确信这可以更快地完成。

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。根目录下的节点可以是hgsoel。您还需要节点来终止字符,以区分gogood

要查找所有匹配项,请使用广度优先搜索方法。您要跟踪的状态是以下内容的组合:搜索字符串中的当前索引,树中的当前节点以及到目前为止使用的单词列表。

初始状态应为0,root,[]

当状态列表不为空时,将下一个状态出列,并查看索引是否与节点子节点的任何键匹配。如果是这样,请修改状态的副本并将其排入队列。此外,如果任何子节点是终止字符,请执行相同的操作,将该单词添加到状态中的列表中。

我不确定此算法的O(n)时间,但它应该快得多。