我正试图找到一种方法来查找连续出现的加扰文本中的特定单词。未找到的字符将具有X
。
例如,假设词典单词列表是:
jane
john
brownbag
foo
youth
和乱序文字:
ofozlhuoyt => fooXXyouth
yuawbnrobgajen => XXbrownbagjane
janjeohn => (nothing since jane and john aren't consecutive)
方法我正在尝试:
说,我有一个密钥a
到z
的哈希值,并设置为每个密钥的值。集合中的每个数字将表示包含特定字符的单词的索引。
从上面的例子:
{a: [0,2]}
{b: [2]}
{c: []}
{e: [0]}
{f: [3]}
{g: [2]}
{h: [1,4]}
{j: [0,1]}
...
{n: [0,1,2]}
{o: [1,2,3,4]}
{r: [2]}
{u: [4]}
{t: [4]}
{w: [2]}
{y: [4]}
...
{z: []}
在准备好上述内容后,我们可以开始查看加扰文本的每个字符:
第一个字符串:ofozlhuoyt
o =>存在于1,2,3和4
从1开始:jane(长度4)
获得4个字符:ofoz
"jane".sort(false) == "ofoz".sort(false)?
如果为false:对2(john)重复步骤1到3
如果为true:将foo添加到好词列表中,并使用z
有更好的方法吗?我觉得有一个更好的数据结构可以解决这样的问题,但我无法弄清楚要使用哪个..
答案 0 :(得分:2)
如果你有足够的内存来实现它,有一种可能更快的方法。
首先,为每个单词生成所有排列。所以对于“简”,你会有:
aejn
aenj
ajen
ajne
anej
anje
etc.
然后,为Aho-Corasick algorithm构建状态机,单个单词的每个排列都进入相同的结束状态。结束状态将输出您正在寻找的字符串。
现在通过状态机运行文本。输出将是找到的单词及其位置。然后,您可以按位置对找到的单词进行排序,并确定它们是否连续出现。
状态机可能非常大(每个单词的n!状态,其中n是单词中的字符数),并且需要一些时间来构建。但是一旦它被构建,它就会很快匹配。如果你的单词列表是静态的,并且你有很多要搜索的文本,那么这就是你要走的路。只要你有足够的记忆。
我使用了一种改进的Aho-Corasick算法,该算法在视频标题中搜索文本中出现的数百万个短语(乐队和歌曲名称)。状态机占用大约10千兆字节的内存并花费了大约一个小时来构建,但是在匹配时它是 fast 。
答案 1 :(得分:2)
你可以使用素数!
当您乘以n素数时,您获得的产品将与其他任何组合的素数不同。
在您的问题中,关键是订单无关紧要,因此排序将浪费时间。换句话说,
'jane' == 'ejna' == 'jnea' == ...
因此,您可以基于cool prime属性创建自己的哈希函数,并使用乘法的交换来避免排序/字符串搜索。在python中,你甚至不必担心整数的大小;如果你的词典里面有很大的词汇,这将会派上用场。
下面是一个简单的dict映射字母到前26个素数,以及随附的散列函数。
letters_to_primes = {'a': 2, 'b': 3, 'c': 5, 'd': 7, ... 'x': 89, 'y': 97, 'z': 101}
def my_prime_hash(word):
sum = 1
for letter in word:
sum = sum * letters_to_primes[letter] # Multiplication is commutative!
return sum
同样,我们在这里利用的关键属性是
my_prime_hash('jane') == my_prime_hash('enaj') == ... == 27434
现在我们只需要创建给定字典单词的dict。我建议使用外部链接哈希表。我们称之为'hashed_words'。
# Given these words
words = ['jane', 'john', 'brownbag', 'foo', 'youth', 'nib', 'bin']
# Compute the hash table
hashed_words = {}
for word in words:
w_hash = my_prime_hash(word)
if w_hash in hashed_words: hashed_words[w_hash].append(word)
else: hashed_words[w_hash] = [word]
运行之后,hashed_words看起来像:
{1113571: ['john'], 27434: ['jane'],
28717: ['foo'], 448956643: ['youth'],
3131090838L: ['brownbag'], 2967: ['nib', 'bin']}
这就是我们想要的。
现在,您可以通过计算字母的产品来开始对乱码字进行散列,并在每个点检查产品是否为hashed_words。类似于其他人提出的状态机对于“mrtasgth”这个混乱的单词中的“mart”和“smart”等情况是必要的(见下面的评论)。
注意:您可以考虑字典中出现的所有字母的频率分布,并将最低素数分配给频率最高的字母,而不是按升序分配素数。这确实会在创建'hashed_words'哈希表时节省内存。
答案 2 :(得分:1)
可能是这样的:
http://en.wikipedia.org/wiki/Rabin-Karp_algorithm
与哈希思想非常相似,与aho-corasick算法相关