有效地分组字谜
Posted
技术标签:
【中文标题】有效地分组字谜【英文标题】:Grouping anagrams efficiently 【发布时间】:2015-12-25 07:34:34 【问题描述】:我正在尝试编写一个程序,将列表中的所有字谜组合在一起,并且输出必须按字母顺序排序。我已经有一个程序可以使用 heapsort 在 O(nlog(n)) 时间内按字母顺序对输入进行排序。我的程序也对字谜进行分组,但是它太慢了。我相信使用散列会给出一个有效的算法,但不太确定如何实现它。有人对完成这项任务的有效算法有什么建议吗?
例如。
输入:
eat tea tan ate nat bat
输出:
ate eat tea
bat
nat tan
【问题讨论】:
你目前的(慢)分组算法是什么? 【参考方案1】:看来你看错了。据我了解,您首先按字母顺序对字符串进行排序,然后尝试将它们分成组。
尝试反其道而行之。首先,将字符串分组为字谜,然后再对每个组进行排序。
可以通过多种方式对字谜进行分组,这里是其中之一:
-
将每个字符串排序为一个字谜。这意味着,每个字谜本身都是排序的。例如:eat,tea,nat 都将被排序到字符串“aet”。 (记住每个单词的原始形式以备后用)。
一旦每个单词都经过“字谜排序”,您就可以简单地使用哈希表将它们全部分组,使用
Map<String,List<String>>
- 其中键是“排序的字谜”,值是包含所有原始字词的列表字。
获得此映射后,您需要对作为此映射中的值的每个列表进行排序,这就是您的最终输出。
【讨论】:
【参考方案2】:是的,它是散列。
您可以使用以下散列技术:(假设您的字符串都没有空格并且只有小写字符,如果它们是大写字母,则将被区别对待(cat 和 Act 不是字谜))
一个字符的哈希值将是它的ascii值的平方,即。
a = 97*97, b = 98*98, etc.
将每个单词的字符值加起来,就是它的哈希值。
现在,将具有相同(相等)哈希值的单词组合在一起。
PS:如果 cat 和 Act 是字谜,在计算之前将 A
转换为 a
。
PPS:为了响应@amit 的 cmets,我将每个字符的 ASCII 值平方以减少冲突,但是,这不会绝对没有冲突。您可以使用 n^th 斐波那契数的平方 作为哈希值,然后将它们相加。这进一步减少了碰撞。 因此,哈希值将类似于:
a = 98^2, b = 99^2, c = (98+99)^2, d = (b+c)^2 and so on...
【讨论】:
假设所有字符都是可行的,这对于"d"
(ascii=100) 和 "\n\n"
(ascii=10 for each) 将失败。
一个单词不能有空格,只能是小写字符。 (假设)
\n
算作空格。
一般来说,如果有一个唯一的素数是每个哈希码的一个因子,它就可以工作(这意味着,对于每个哈希码x
,都有一个素数p
,它是一个x
的因子,而不是每个哈希码 y!=x
的因子。
哦,更正。您将值相加,而不是多个值。这听起来更糟糕。例如 - 一个由 98*98 个字符组成的字符串,所有 a's 将具有与包含 97*97 个字符,所有 b's 的字符串相同的哈希码。以上是关于有效地分组字谜的主要内容,如果未能解决你的问题,请参考以下文章