代码之家  ›  专栏  ›  技术社区  ›  Greg K

如何递归地平衡括号

  •  4
  • Greg K  · 技术社区  · 13 年前

    我正在编写一些代码来平衡括号, this question 证明对该算法最有用。

    我用我的第一语言(PHP)实现了它,但我正在学习Scala并尝试转换代码。

    以下是我的PHP代码:

    function balanced($string) {
      return isBalanced($string, "");
    }
    
    function isBalanced($chars, $stack) {
      if (!strlen($chars))
        return empty($stack);
    
      switch ($chars[0]) {
        case '(':
          // prepend stack with '(', move to next character
          return isBalanced(substr($chars, 1), $chars[0] . $stack);
        case ')':
          // if '(' seen previously, shift stack, move to next character
          return !empty($stack) && isBalanced(substr($chars, 1), substr($stack, 1));
        default:
          // do nothing to stack, move to next character
          return isBalanced(substr($chars, 1), $stack);
      }
    } 
    

    我已经测试过了,它有效。然而,当我将它转换为Scala时,它在平衡字符串上失败了。

    我的Scala代码:

    object Main {
      def balance(chars: List[Char]): Boolean = {
        def balanced(chars: List[Char], stack: String): Boolean = {
          if (chars.isEmpty)
            stack.isEmpty
          else if (chars.head == ')')
            balanced(chars.tail, chars.head + stack)
          else if (chars.head == '(')
            !stack.isEmpty && balanced(chars.tail, stack.tail)
          else
            balanced(chars.tail, stack)
        }
    
        balanced(chars, "")
      }
    }
    

    我很感激这不是最好的Scala代码,但我才刚刚开始。一些测试:

    balance("(if (0) false (x))".toList) - fails
    balance("profit and loss (P&L).\n(cashflow)".toList) - fails
    balance(":)".toList) - passes
    balance(")(()".toList) - passes
    

    PHP等效程序通过了所有这些测试。我在Scala实现中做错了什么?

    9 回复  |  直到 7 年前
        1
  •  24
  •   Aaron Novstrup    13 年前

    值得一提的是,这里有一个更惯用的Scala实现:

    def balance(chars: List[Char]): Boolean = {
      @tailrec def balanced(chars: List[Char], open: Int): Boolean = 
        chars match {
          case      Nil => open == 0
          case '(' :: t => balanced(t, open + 1)
          case ')' :: t => open > 0 && balanced(t, open - 1)
          case   _ :: t => balanced(t, open)
        }
    
      balanced(chars, 0)
    }
    
        2
  •  9
  •   Community Mohan Dere    9 年前

    为了完整起见,我从中找到了一个更简洁的“scala-sque”实现 another SO question 以下为:

    def balance(chars: List[Char]): Boolean = chars.foldLeft(0){
      case (0, ')') => return false
      case (x, ')') => x - 1
      case (x, '(') => x + 1
      case (x, _  ) => x
    } == 0
    
        3
  •  9
  •   Vigneshwaran jayunit100    13 年前

    与Aaron Novstrup的答案相同,但使用了“if else”。我也参加了同一门课程,但我们的课程只到目前为止。

    def balance(chars: List[Char]): Boolean = {
        def balanced(chars: List[Char], open: Int): Boolean = 
          if (chars.isEmpty) open == 0
          else if (chars.head == '(') balanced(chars.tail, open + 1)
          else if (chars.head == ')') open > 0 && balanced(chars.tail, open - 1)
          else balanced(chars.tail, open)
        balanced(chars, 0)
    }
    
        4
  •  8
  •   Kim Stebel    13 年前

    你把案子搞混了 ( )

        5
  •  3
  •   Chaitanya Kumar    9 年前

    您可以使用递归以高效的方式解决问题,而不是使用Switch案例。

    下面是我的代码,在递归的帮助下实现同样的目的。对于我的方法,您需要将字符串转换为List。

    代码:

    object Balance {
    
      def main(args: Array[String]): Unit = {
        var paranthesis = "(234(3(2)s)d)" // Use your string here
        println(bal(paranthesis.toList)) // converting the string to List 
      }
    
      def bal(chars: List[Char]): Boolean ={
       // var check  = 0
        def fun(chars: List[Char],numOfOpenParan: Int): Boolean = {
          if(chars.isEmpty){
            numOfOpenParan == 0
          }
          else{
            val h = chars.head
    
            val n = 
              if(h == '(') numOfOpenParan + 1
              else if (h == ')') numOfOpenParan - 1
              else numOfOpenParan 
    
           // check  = check + n
            if (n >= 0) fun(chars.tail,n)
            else false 
          }
        }
        fun(chars,0)
      }
    }
    
        6
  •  0
  •   Anuj Mehta    12 年前

    我的解决方案

    def balance(chars: List[Char]): Boolean = {
     var braceStack = new Stack[Char]()
    
    def scanItems(strList:List[Char]):Boolean = {
       if(strList.isEmpty)
           braceStack.isEmpty
       else{
          var item = strList.head
          item match {
            case '(' => braceStack.push(item)
                        scanItems(strList.tail)
            case ')'=> if(braceStack.isEmpty){
                            false
                        }
                        else {
                          braceStack.pop
                          scanItems(strList.tail)
                        }
            case _ => scanItems(strList.tail)
          }
        }
     }
    
     scanItems(chars)
    

    }

        7
  •  0
  •   sivaji kondapalli    12 年前
      val myStack = new Stack[Char]
    
      def balance(chars: List[Char]): Boolean = {
        def processParanthesis(x: Char, a: List[Char]): Stack[Char] = {
          if (x == '(') {
            myStack.push('(');
          } else if (x == ')') {
            if (!myStack.empty())
              myStack.pop();
            else
              myStack.push(')');
          }
          if (a.length == 0)
            return myStack;
          else
            return processParanthesis(a.head, a.tail);
        }
        return processParanthesis(chars.head, chars.tail).empty();
      }
    
        8
  •  0
  •   alt-f4    6 年前

    添加到Vigneshwaran的答案(包括注释和过滤不必要的字母以避免额外的递归调用):

    def balance(chars: List[Char]): Boolean = {
      @scala.annotation.tailrec
      def recurs_balance(chars: List[Char], openings: Int): Boolean = {
        if (chars.isEmpty) openings == 0
        else if (chars.head == '(') recurs_balance(chars.tail, openings + 1)
        else openings > 0 && recurs_balance(chars.tail, openings - 1)
      }
    
      recurs_balance(chars.filter(x => x == '(' || x == ')'), 0)
    }
    
        9
  •  -2
  •   user62058    13 年前

    看来我们上的是同一门课。我的解决方案:

    def balance(chars: List[Char]): Boolean = 
    doBalance(chars, 0) == 0;
    def doBalance(chars: List[Char], parenthesisOpenCount: Int): Int =
    if(parenthesisOpenCount <0) -100;
    else
    if(chars.isEmpty) parenthesisOpenCount
    else
      chars.head match {
      case '(' => return doBalance(chars.tail, parenthesisOpenCount+1) 
      case ')' => return doBalance(chars.tail, parenthesisOpenCount-1)
      case _ => return doBalance(chars.tail, parenthesisOpenCount)
    }