如何在Scala中找到两个字符串之间的最大重叠?

时间:2014-08-03 13:20:05

标签: string scala

假设我有两个字符串:st。我需要编写一个函数f来查找最大值。 t前缀,也是s后缀。例如:

 s = "abcxyz", t = "xyz123", f(s, t) = "xyz"
 s = "abcxxx", t = "xx1234", f(s, t) = "xx"

你会怎么用Scala写的?

3 个答案:

答案 0 :(得分:4)

这个第一个解决方案很简单,也比递归版本更有效,因为它使用了一个懒惰的迭代评估

s.tails.find(t.startsWith).get

现在已经讨论过tails是否会反复复制整个字符串。在这种情况下,您可以toList使用s,然后使用mkString结果。

s.toList.tails.find(t.startsWith(_: List[Char])).get.mkString

由于某种原因,需要使用类型注释来进行编译。我实际上并没有尝试看哪一个更快。

更新 - 优化

正如som-snytt指出的那样,t不能以任何比它长的字符串开头,因此我们可以进行以下优化:

s.drop(s.length - t.length).tails.find(t.startsWith).get

答案 1 :(得分:3)

如果我们只需要找到公共重叠部分,那么我们可以递归地获取第一个字符串的尾部(它应该与第二个字符串的开头重叠),直到剩下的部分不是第二个字符串开头的部分。 。这也涵盖了字符串没有重叠的情况,因为那时将返回空字符串。

scala> def findOverlap(s:String, t:String):String = { 
    if (s == t.take(s.size)) s else findOverlap (s.tail, t) 
}
findOverlap: (s: String, t: String)String

scala> findOverlap("abcxyz", "xyz123")
res3: String = xyz

scala> findOverlap("one","two")
res1: String = ""

更新:有人指出tail可能无法以最有效的方式实现(即它在调用时会创建一个新字符串)。如果这成为问题,那么使用substring(1)代替tail(或将两个字符串转换为列表,其尾部/头部应具有O(1)复杂度)可能会提供更好的性能。同样,我们可以将t.take(s.size)替换为t.substring(0,s.size)

答案 2 :(得分:3)

效率高,这不是,但它是一个整洁的(IMO)单线。

val s = "abcxyz"
val t ="xyz123"

(s.tails.toSet intersect t.inits.toSet).maxBy(_.size)
 //res8: String = xyz

(取s的所有后缀,也是t的前缀,并选择最长的)