Scala:使用素数的两个字符串的字谜

时间:2014-04-03 12:46:57

标签: string scala sorting hash

解决!

我正在研究一个检查两个字符串是否为字谜的函数。简单版本将两个字符串转换为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。

1 个答案:

答案 0 :(得分:3)

你有一个错字:比较hashof相同的值(t)

else if(PrimeHash.hashOf(t).equals(PrimeHash.hashOf(t))) true