从字典中获取字谜列表
Posted
技术标签:
【中文标题】从字典中获取字谜列表【英文标题】:get list of anagrams from a dictionary 【发布时间】:2012-06-21 22:32:47 【问题描述】:基本上,字谜就像字符串的排列。例如 stack
,sackt
,stakc
都是stack
的字谜(认为上面的词没有意义)。不管怎样,你本可以理解我的基本意思。
现在,我想要一个anagrams
的列表,给定百万个单词,或者简单地从字典中说出来。
我的基本问题是Find total number of unique anagrams in a dictionary?
排序和比较 不会工作,因为它的时间复杂度非常糟糕。
我想到了使用哈希表,字符串作为键。
但问题是散列函数应该是什么?如果有一些伪代码会很有帮助 假如。其他一些比上述方法更好的方法也会有所帮助。
谢谢。
【问题讨论】:
问题不太清楚。你能改述一下目标吗? 您的意思是:我有一本包含一百万个单词的字典,我希望识别字典中所有相互变位的单词集?例如。如果字典包含:[tap, pat, pot, top] 您希望看到 [[tap, pat], [pot, top]]? 是的@Alex。我只想知道有多少不同的字谜? @NicholasDiPiazza 希望你,我的目标很清楚。 排序是这里的解决方案,如果你假设字长有一些恒定的上限,它的复杂性是线性的。你只需要排序正确的东西;字符,而不是单词。 【参考方案1】:显而易见的解决方案是将每个字符映射到一个素数并乘以这些素数。所以如果 'a'' -> 2 和 'b' -> 3,那么
'ab' -> 6 'ba' -> 6 'bab' -> 18 '阿巴' -> 36 'baba' -> 36为了最小化溢出的机会,最小的素数可以分配给更频繁的字母(e,t,i,a,n)。注意:第 26 个素数是 101。
更新: an implementation can be found here
【讨论】:
你仍然需要处理溢出,这可能会导致“冲突”。可能是通过存储每个条目的字母频率直方图。 嗯:谢谢!请注意(一旦你必须处理冲突)它也适用于非质数(random)数字。这类似于 Zobrist 散列。但使用素数时,它看起来更干净。【参考方案2】:一个可能的散列函数可以是(假设只有英文单词)每个字母出现次数的排序计数。因此,对于“字谜”,您将生成 [('a', 3), ('g', 1), ('n', 1), ('m', 1), ('r',1)]。
或者,您可以通过从您的单词生成位掩码来获得不精确的分组,其中对于位 0-25,每个位表示该字母的存在或不存在(位 0 表示“a”到位 25 表示“z”)。但是随后您必须进行更多处理以进一步拆分每个散列组以区分例如“to”从“too”。
这些想法有帮助吗?任何特定的实现语言(我可以使用 C++、python 或 Scala)?
编辑:添加了一些示例 Scala 代码和输出:
好的:我现在处于 Scala 模式,所以我已经敲定了一些东西来做你所要求的,但是(咳咳)如果你对 Scala 或函数式编程不太熟悉,可能不太清楚.
从这里使用大量英语单词:http://scrapmaker.com/data/wordlists/twelve-dicts/2of12.txt
我在它们上运行这个 Scala 代码(在脚本模式下使用 Scala 2.9 大约需要 5 秒,包括编译时间,字典大约 40,000 个单词。不是最有效的代码,但首先想到的) .
// Hashing function to go from a word to a sorted list of letter counts
def toHash(b:String) = b.groupBy(x=>x).map(v => (v._1, v._2.size) ).toList.sortWith(_._1 < _._1)
// Read all words from file, one word per line
val lines = scala.io.Source.fromFile("2of12.txt").getLines
// Go from list of words to list of (hashed word, word)
val hashed = lines.map( l => (toHash(l), l) ).toList
// Group all the words by hash (hence group all anagrams together)
val grouped = hashed.groupBy( x => x._1 ).map( els => (els._1, els._2.map(_._2)) )
// Sort the resultant anagram sets so the largest come first
val sorted = grouped.toList.sortWith( _._2.size > _._2.size )
for ( set <- sorted.slice(0, 10) )
println( set._2 )
这会导出前 10 组字谜(首先是成员最多的一组):
List(caret, cater, crate, react, trace)
List(reins, resin, rinse, risen, siren)
List(luster, result, rustle, sutler, ulster)
List(astir, sitar, stair, stria, tarsi)
List(latrine, ratline, reliant, retinal)
List(caper, crape, pacer, recap)
List(merit, miter, remit, timer)
List(notes, onset, steno, stone)
List(lair, liar, lira, rail)
List(drawer, redraw, reward, warder)
请注意,这使用了第一个建议(字母计数列表),而不是更复杂的位掩码方法。
编辑 2:您可以将哈希函数替换为对每个单词的字符进行简单排序(如 JAB 建议的那样),并使用更清晰/更快的代码获得相同的结果:
def toHash(b:String) = b.toList.sortWith(_<_)
【讨论】:
你能帮我解释一下算法吗。那会很有帮助的。【参考方案3】:如果你对每个字符的哈希码值进行异或,然后通过输入长度对结果进行异或,无论单词的顺序如何,你都会得到相同的值,这意味着所有的字谜都会产生相同的哈希值。 (长度异或可以防止 'boss' 和 'bo' 返回相同的值,因为 's' 与自身的哈希值始终为 0。)
例子:
int AnagramHash(string input)
int output = 0;
foreach(char c in input)
output ^= c.GetHashCode();
return output ^ input.Length;
您仍然需要搜索所有具有相同 AnagramHash 的单词。我会使用哈希字段更新字典表(无论您的算法如何)以减少整体计算。
编辑: 另外,作为一个旁注,XOR 是 ALU 执行的最简单的操作,所以如果你最终使用它,你应该能够相当快地生成你的哈希。
【讨论】:
在 C# 中,GetHashCode()
是所有类的方法。它本质上为任何对象生成一个唯一的整数值。 (具有相同值的对象将产生相同的整数。)对于不同的语言,您可以只使用每个字符的字节值作为哈希码,因为它们对于每个值仍然是唯一的。
"您仍然需要搜索所有具有相同 AnagramHash 的单词。"如果您将单词放在列表/等中,则不会。存储在AnagramHash
指定的字典中的位置。
如果我使用素数来编码每个字符有什么问题吗?【参考方案4】:
排序和比较不起作用,因为它的时间复杂度非常糟糕。
将时间复杂度换成额外的内存,只需将单词中的字母计数存储在 26-char
中(或您使用的任何语言的等价物,并假设您使用的是罗马字母并且仅字母字符)数组和散列数组。相对于单词长度,您会遇到 O(n) 时间,但大多数英语单词并没有那么长。
例如stack
、sackt
和 stakc
都会有一个数组,其中的位置为 s
、t
、a
、c
、k
== 1,其余的都设置为 0 .
根据您的评论,这意味着您确实可以对单词的字符进行排序,只要您不对单词本身进行排序,您可以做一些比 Alex 的回答更简单的事情,只需对单词中的字符进行排序字符串并对结果进行哈希处理。 (larsmans 先说了,但没有把它作为答案发布,所以......)
【讨论】:
基本上,我担心时间复杂度。看看其他答案。我认为它会处理这两种复杂性。谢谢 可以,但是你说你不想排序,所以我给你一些不涉及排序的东西。 谢谢。对不起,我迷路了:P Alex 没有对字符进行排序。他正在对单词中的字符进行排序计数,这非常酷。无论如何,谢谢你的帮助。 JAB 是正确的 - 对字符进行排序(只要您仍然保留重复项)并将其用作散列将很好地工作 - 实际上可能比从 chars 到的列表更优雅和高效我建议的很重要。【参考方案5】:使用以字符串为键并以列表(字符串)为值的哈希图,其中字符串列表包含键字符串的所有字谜。
问题类似于“查找文件中某个单词的所有字谜”
在此处查看算法和代码http://justprogrammng.blogspot.com/2012/06/determine-anagrams-of-word-in-file.html
【讨论】:
以上是关于从字典中获取字谜列表的主要内容,如果未能解决你的问题,请参考以下文章