【问题标题】:Scala: Make sure braces are balancedScala:确保大括号是平衡的
【发布时间】:2018-06-10 10:04:38
【问题描述】:

我正在运行一个代码来平衡语句中的括号。我想我已经猜对了,但它在一个特定的陈述上失败了,我需要了解为什么?

这是特别失败的测试“())(”

我认为我需要修复算法的不仅仅是编码,还有任何指针吗?

def balance(chars: List[Char]): Boolean = {

  def find(c: Char, l: List[Char], i: Int): Int={
    if( l.isEmpty ) {
      if(c=='(')
        i+1
      else if(c==')')
        i-1
      else
        i
    }
    else if (c=='(')
      find(l.head, l.tail, i+1)
    else if(c==')')
      find(l.head,l.tail, i-1)
    else
      find(l.head,l.tail, i)

  }

  if(find(chars.head, chars.tail,0) ==0 )
     true
  else
     false

}


balance("())(".toList) //passes when it should fail
balance(":-)".toList)
balance("(if (zero? x) max (/ 1 x))".toList)
balance("I told him (that it's not (yet) done).\n(But he wasn't listening)".toList)

【问题讨论】:

  • 此模式")(") 开头,这意味着您的i 值变为负数,这是不允许的,但您永远不会测试i 值,除非最后,在最终的( 将其归零之后。
  • 另外,Coursera。这个想法是你自己调试你的问题,你可以通过这种方式了解更多

标签: scala recursion balance


【解决方案1】:

这是一个版本:

def balance(chars: List[Char]): Boolean = {
    def inner(c: List[Char], count: Int): Boolean = c match {
        case Nil                   => count == 0           // Line 1
        case ')' :: _ if count < 1 => false                // Line 2
        case ')' :: xs             => inner(xs, count - 1) // Line 3
        case '(' :: xs             => inner(xs, count + 1) // Line 4
        case _ :: xs               => inner(xs, count)     // Line 5
    }
    inner(chars, 0)
}

所以在您的代码中,当您遇到正确的括号时,我认为您缺少对 count

【讨论】:

    【解决方案2】:

    您犯了一个非常简单且完全可以理解的错误。根据您当前的定义,)( 中的括号是平衡的。只是它们不像我们通常认为的那样平衡。在第一个字符之后,你有 -1 未闭合的括号,然后在第二个字符之后我们又回到 0,所以一切都很好。 如果括号计数低于零,则括号不可能平衡

    现在有两种真正的方法来处理这个问题。快速而肮脏的解决方案是抛出异常。

    case object UnbalancedException extends Exception
    
    if (i < 0)
      throw UnbalancedException
    

    然后在 balance 中捕获并返回 false。

    try {
      ... // find() call goes in here
    } catch {
      case UnbalancedException => false
    }
    

    更实用的解决方案是让find 返回Option[Int]。在递归期间,如果您得到None 结果,则返回None。否则,正常运行并返回Some(n)。如果您遇到i &lt; 0 的情况,则返回None 表示失败。然后在balance 中,如果结果为非零结果为@​​987654333@,则返回false。这可以用for 表示法变得更漂亮,但如果你刚刚开始,那么手写它会很有帮助。

    【讨论】:

    • 没有必要返回Option:只要遇到负数就可以了
    【解决方案3】:

    您也可以使用Stack data structure 的属性来解决这个问题。当你看到开括号时,你将它推入堆栈。当你看到右括号时,你会从堆栈中弹出(而不是我使用 List 的堆栈,因为不可变 Stack is deprecated in Scala):

    def isBalanced(chars: Seq[Char]): Boolean = {
      import scala.annotation.tailrec
    
      case class BracketInfo(c: Char, idx: Int)
      def isOpen(c: Char): Boolean = c == '('
      def isClose(c: Char): Boolean = c == ')'
      def safePop[T](stack: List[T]): Option[T] = {
        if (stack.length <= 1) stack.headOption
        else stack.tail.headOption
      }
    
      @tailrec
      def isBalanced(chars: Seq[Char], idx: Int, stack: List[BracketInfo]): Boolean = {
        chars match {
          case Seq(c, tail@_*) =>
            val newStack = BracketInfo(c, idx) :: stack // Stack.push
            if (isOpen(c)) isBalanced(tail, idx + 1, newStack)
            else if (isClose(c)) {
              safePop(stack) match {
                case Some(b) => isBalanced(tail, idx + 1, stack.tail)
                case None =>
                  println(s"Closed bracket '$c' at index $idx was not opened")
                  false
              }
            }
            else isBalanced(tail, idx + 1, stack)
          case Seq() =>
            if (stack.nonEmpty) {
              println("Stack is not empty => there are non-closed brackets at positions: ")
              println(s"${stack.map(_.idx).mkString(" ")}")
            }
            stack.isEmpty
        }
      }
    
      isBalanced(chars, 0, List.empty[BracketInfo])
    }
    

    【讨论】:

      【解决方案4】:

      使用map

      def balance(chars: List[Char]): Boolean = {
          chars.map(c =>
             c match {
               case '(' => 1
               case ')' => -1
               case _ => 0
             }
          ).scanLeft(0)(_ + _).dropWhile(_ >= 0).isEmpty
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多