一个可能的散列函数可以是(假设只有英文单词)每个字母出现次数的排序计数。因此,对于“字谜”,您将生成 [('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(_<_)