如何在Scala中找到两个字符串的最长公共前缀?

时间:2011-11-12 12:37:13

标签: string scala list-comprehension

如何在Scala中找到两个字符串的最长公共前缀?

我可能可以编写一个“命令式”解决方案(索引i在字符串s(i) == t(i)上运行),但我正在寻找一种“功能式”解决方案(不更新索引变量)明确地,例如)。

8 个答案:

答案 0 :(得分:26)

scala> "helloworld".zip("hellohell").takeWhile(Function.tupled(_ == _)).map(_._1).mkString
res130: String = hello

答案 1 :(得分:4)

另一个递归版本。

def pref(s: String, t: String, out: String = ""): String = {
  if (s == "" || t == "" || s(0) != t(0)) out
  else pref(s.substring(1), t.substring(1), out + s(0))
}

它比sjj快10倍以上,比missfaktor快两倍。 Java的substring很快,因为String是不可变的。

答案 2 :(得分:3)

递归版:

def findCommonPrefix(s1 : String, s2 : String) : String = {
    def findCommonPrefixR(l1: List[Char], l2 : List[Char]) : List[Char] = {
        l1 match {
        case Nil => Nil
        case x::xs => if (l2 != Nil && l2.head == x) x :: findCommonPrefixR(xs, l2.tail) else Nil
        }
    }
    findCommonPrefixR(s1.toList, s2.toList).mkString
}

答案 3 :(得分:2)

命令式版本可以简化为

def longestCommonPrefix(s1:String, s2:String):String = {
  val maxSize = scala.math.min(s1.length, s2.length)
  var i:Int = 0;
  while ( i < maxSize && s1(i)== s2(i)) i += 1;
  s1.take(i);
}

答案 4 :(得分:1)

如果速度是合约,那么就必须采取行动。

scala> def longestCommonPrefix(a: String, b: String): String = {
     |   var same = true
     |   val sb = new StringBuilder
     |   var i = 0
     |   while(same && i < math.min(a.length, b.length)) {
     |     if(a.charAt(i) != b.charAt(i)) {
     |       same = false
     |     } else {
     |       sb += a.charAt(i)
     |       i += 1
     |     }
     |   }
     |   sb.result
     | }
longestCommonPrefix: (a: String, b: String)String

scala> longestCommonPrefix("", "")
res50: String = ""

scala> longestCommonPrefix("helloworld", "hellohell")
res51: String = hello

编辑:

根据Luigi的建议:

scala> def longestCommonPrefix(a: String, b: String): String = {
     |   var same = true
     |   var i = 0
     |   while(same && i < math.min(a.length, b.length)) {
     |     if(a.charAt(i) != b.charAt(i)) {
     |       same = false
     |     } else {
     |       i += 1
     |     }
     |   }
     |   a.substring(0, i)
     | }
longestCommonPrefix: (a: String, b: String)String

scala> longestCommonPrefix("helloworld", "hellohell")
res68: String = hello

答案 5 :(得分:0)

获取任意数量字符串的公共前缀:

def commonPrefix (strs: Seq[String]): String = {
  var i = 0;
  strs(0).takeWhile { ch => strs.forall(_(i) == ch) && {i += 1; true}} mkString
} 

答案 6 :(得分:0)

def commonPrefix(strings: String*): String = {
  val refString = strings.map(s => (s, s.length())).minBy { case (string, length) => length }._1
  var i = 0
  while (i < refString.length) {
    if (!strings.forall(_(i) == refString(i))) return refString.substring(0, i)
    i += 1
  }
  return refString
}

答案 7 :(得分:0)

根据每个OP请求,下面是一个简单的最佳快速的“功能样式”实现。

此实现与任何手写的可变命令式样式一样快(因为它是尾部递归的)。

def takeCommonPrefix(string1: String, string2: String): String = {
  if (string1.nonEmpty && string2.nonEmpty) {
    val (shorter, longer) =
      if (string1.length < string2.length) (string1, string2)
      else (string2, string1)

    @scala.annotation.tailrec
    def recursive(shorterIndex: Int = 0): String =
      if (shorterIndex == shorter.length)
        shorter
      else
        if (shorter(shorterIndex) != longer(shorterIndex))
          shorter.take(shorterIndex)
        else
          recursive(shorterIndex + 1)

    recursive()
  }
  else
    ""
}

作为奖励,如果您想要公用前缀,那么很有可能迫在眉睫。

  def takeCommonSuffix(string1: String, string2: String): String = {
    if (string1.nonEmpty && string2.nonEmpty) {
      val (shorter, longer) =
        if (string1.length < string2.length) (string1, string2)
        else (string2, string1)
      val longerOffset =
        longer.length - shorter.length

      @scala.annotation.tailrec
      def recursive(shorterIndex: Int = shorter.length - 1): String =
        if (shorterIndex == -1)
          shorter
        else
          if (shorter(shorterIndex) != longer(shorterIndex + longerOffset))
            shorter.takeRight(shorter.length - shorterIndex - 1)
          else
            recursive(shorterIndex - 1)

      recursive()
    }
    else
      ""
  }