【问题标题】:How to balance parenthesis recursively如何递归地平衡括号
【发布时间】:2012-09-15 07:55:34
【问题描述】:

我正在编写一些代码来平衡括号,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 实现中做错了什么?

【问题讨论】:

  • 看起来你只是混淆了'('')' 的情况:)
  • 噢!谢谢 - 我一直盯着这段代码太久了:)
  • Ben,如果您将其发布为答案,我认为您应该获得第一名的声誉。
  • 哈哈 - 我很高兴你这么认为,但我太自豪了,不能因为这样一件微不足道的事情而享有声誉;)
  • Greg K:抱歉,没有看到你的评论

标签: scala recursion


【解决方案1】:

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

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)
}

【讨论】:

    【解决方案2】:

    您可以使用递归来有效地解决您的问题,而不是使用 Switch case。

    以下是我在递归的帮助下实现相同目的的代码。您需要为我的方法将字符串转换为 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)
      }
    }
    

    【讨论】:

      【解决方案3】:
        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();
        }
      

      【讨论】:

        【解决方案4】:

        我的解决方案

        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)
        

        }

        【讨论】:

          【解决方案5】:

          与 Aaron Novstrup 的回答相同,但使用“if else”。我也参加了同一门课程,但到目前为止我们只学习了 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)
          }
          

          【讨论】:

            【解决方案6】:

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

            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)
            }
            

            【讨论】:

              【解决方案7】:

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

              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
              

              【讨论】:

                【解决方案8】:

                不管怎样,这里有一个更惯用的 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)
                }
                

                【讨论】:

                • 看起来你需要在 open parens case 中将 'count' 替换为 'open'。
                【解决方案9】:

                您混淆了() 的情况。

                【讨论】:

                  猜你喜欢
                  • 2013-11-18
                  • 1970-01-01
                  • 2015-10-18
                  • 2011-02-12
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-10-22
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多