解决!
我正在研究一个检查两个字符串是否为字谜的函数。简单版本将两个字符串转换为CharArray,对它们进行排序并比较两个数组。这是有效的,因为Anagrams一旦排序就会以相同的顺序排列。例如,上帝,狗 两者都排序“dgo”
def isAnagram2(s : String , t : String ) : Boolean = {
if(s == null || t == null || s.length != t.length) false
val str1: Array[Char] = s.toCharArray
val str2: Array[Char] = t.toCharArray
sort(str1)
sort(str2)
equals(str1, str2)
}
上面的代码编译并在Scala 2.10上运行。输出为:
apple, papel: true
carrot, tarroc: true
hello, llloh: false
abba, xyzz: false
然而,这不是非常有效,因为排序两次占用非常长的字符串。 根据这篇文章:Comparing anagrams using prime numbers。
检查字符串的两个字符串的最快方法是使用素数作为散列函数。
主要思想是:
假设两个字符串的长度相同......
1)使用简单替换每个字符生成哈希,即 b - > 3
2)乘以所有哈希值,因为素数是乘法唯一的
3)将StringA的prime-hash与StringB进行比较
如果两个字符串具有相同的长度并且由相同的字符组成,则它们应具有相同的主要哈希值。
例如 'cat'和'act'想要
sum_act = int(a)+ int(c) sum_cat = int(c)+ int(a)
所以sum_act == sum_cat
重点是,这个版本与顺序无关,因此不需要排序,并且每个字符的查找时间都是恒定的。
在实践中,我有一个PrimeHash对象:
object PrimeHash{
private[this] final val primeAlphabet: Map[Char, Int] = Map('a' -> 2, 'b' .., 'z' -> 101)
def hashOf(string : String): Int = {
string.trim().toLowerCase.foldLeft(1) { (hash, c) => hash * primeAlphabet(c)}
}
}
并使用hashOf函数,如下所示:
def isAnagram(s : String , t : String ) : Boolean ={
if(s == null || t == null || s.length != t.length) false
else if(PrimeHash.hashOf(s).equals(PrimeHash.hashOf(t))) true
else false
}
然而,我的简单测试用例无法检测到非字谜。这是测试代码:
def main(args: Array[String]): Unit = {
val pairs = Array(Array("apple", "papel"), Array("carrot", "tarroc"),Array("hello", "llloh"),Array("abba", "xyzz"))
for(p <- pairs){
val word1 = p(0)
val word2 = p(1)
val anagram = isAnagram2(word1, word2)
println(word1 + ", " + word2 + ": " + anagram)
}
}
排序功能正确地检测到两个“错误”对,但不是哈希值。
github上的完整代码:https://gist.github.com/marvin-hansen/9953592
我不完全确定hashOf函数是否正确
解决方案:固定类型导致hashof与自身的值相同(t)。 感谢mesutozer。
答案 0 :(得分:3)
你有一个错字:比较hashof相同的值(t)
else if(PrimeHash.hashOf(t).equals(PrimeHash.hashOf(t))) true