43

I've written software in the past that uses a stack to check for balanced equations, but now I'm asked to write a similar algorithm recursively to check for properly nested brackets and parenthesis.

Good examples: () [] () ([]()[])

Bad examples: ( (] ([)]

Suppose my function is called: isBalanced.

Should each pass evaluate a smaller substring (until reaching a base case of 2 left)? Or, should I always evaluate the full string and move indices inward?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
pws5068
  • 2,224
  • 4
  • 35
  • 49

12 Answers12

58

First, to your original question, just be aware that if you're working with very long strings, you don't want to be making exact copies minus a single letter each time you make a function call. So you should favor using indexes or verify that your language of choice isn't making copies behind the scenes.

Second, I have an issue with all the answers here that are using a stack data structure. I think the point of your assignment is for you to understand that with recursion your function calls create a stack. You don't need to use a stack data structure to hold your parentheses because each recursive call is a new entry on an implicit stack.

I'll demonstrate with a C program that matches ( and ). Adding the other types like [ and ] is an exercise for the reader. All I maintain in the function is my position in the string (passed as a pointer) because the recursion is my stack.

/* Search a string for matching parentheses.  If the parentheses match, returns a
 * pointer that addresses the nul terminator at the end of the string.  If they
 * don't match, the pointer addresses the first character that doesn't match.
 */
const char *match(const char *str)
{
        if( *str == '\0' || *str == ')' ) { return str; }
        if( *str == '(' )
        {
                const char *closer = match(++str);
                if( *closer == ')' )
                {
                        return match(++closer);
                }
                return str - 1;
        }

        return match(++str);
}

Tested with this code:

    const char *test[] = {
            "()", "(", ")", "", "(()))", "(((())))", "()()(()())",
            "(() ( hi))) (())()(((( ))))", "abcd"
    };

    for( index = 0; index < sizeof(test) / sizeof(test[0]); ++index ) {
            const char *result = match(test[index]);

            printf("%s:\t", test[index]);
            *result == '\0' ? printf("Good!\n") :
                    printf("Bad @ char %d\n", result - test[index] + 1);
    }

Output:

(): Good!
(:  Bad @ char 1
):  Bad @ char 1
:   Good!
(())):      Bad @ char 5
(((()))):   Good!
()()(()()): Good!
(() ( hi))) (())()(((( )))):    Bad @ char 11
abcd:       Good!
indiv
  • 17,306
  • 6
  • 61
  • 82
  • 10
    +1 for showing how to utilize the call stack instead of having an explicit one. I thought it was quite strange that no one had provided an answer showing that yet... Still, this would have looked better in Lisp ;) – wasatz Apr 27 '10 at 17:14
  • @Sid: When I run the test program on `())(`, I get "Bad @ char 3", which looks good to me. http://ideone.com/e.js/VBM8IU – indiv Apr 11 '15 at 22:09
  • 1
    +1, though it would be good to have a (non-recursive) wrapper function `is_balanced` that delegates to this one. The whole "returns a pointer to the first mismatch" thing is really an implementation detail that callers shouldn't have to understand. – ruakh Mar 02 '17 at 01:24
50

There are many ways to do this, but the simplest algorithm is to simply process forward left to right, passing the stack as a parameter

FUNCTION isBalanced(String input, String stack) : boolean
  IF isEmpty(input)
    RETURN isEmpty(stack)
  ELSE IF isOpen(firstChar(input))
    RETURN isBalanced(allButFirst(input), stack + firstChar(input))
  ELSE IF isClose(firstChar(input))
    RETURN NOT isEmpty(stack) AND isMatching(firstChar(input), lastChar(stack))
      AND isBalanced(allButFirst(input), allButLast(stack))
  ELSE
    ERROR "Invalid character"

Here it is implemented in Java. Note that I've switched it now so that the stack pushes in front instead of at the back of the string, for convenience. I've also modified it so that it just skips non-parenthesis symbols instead of reporting it as an error.

static String open  = "([<{";
static String close = ")]>}";

static boolean isOpen(char ch) {
    return open.indexOf(ch) != -1;
}
static boolean isClose(char ch) {
    return close.indexOf(ch) != -1;
}
static boolean isMatching(char chOpen, char chClose) {
    return open.indexOf(chOpen) == close.indexOf(chClose);
}

static boolean isBalanced(String input, String stack) {
    return
        input.isEmpty() ?
            stack.isEmpty()
        : isOpen(input.charAt(0)) ?
            isBalanced(input.substring(1), input.charAt(0) + stack)
        : isClose(input.charAt(0)) ?
            !stack.isEmpty() && isMatching(stack.charAt(0), input.charAt(0))
              && isBalanced(input.substring(1), stack.substring(1))
        : isBalanced(input.substring(1), stack);
}

Test harness:

    String[] tests = {
        "()[]<>{}",
        "(<",
        "]}",
        "()<",
        "(][)",
        "{(X)[XY]}",
    };
    for (String s : tests) {
        System.out.println(s + " = " + isBalanced(s, ""));
    }

Output:

()[]<>{} = true
(< = false
]} = false
()< = false
(][) = false
{(X)[XY]} = true
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • 1
    if the question is check if parenthesis are balanced using recursion, you don't want to explicit pass a stack as an arg of the recursive function – dynamic May 13 '16 at 15:33
  • 6
    This ternary nesting makes this really hard to read. This isn't code golf. You can use explicit flow of control. . – Rig Aug 30 '16 at 03:45
3

The idea is to keep a list of the opened brackets, and if you find a closing brackt, check if it closes the last opened:

  • If those brackets match, then remove the last opened from the list of openedBrackets and continue to check recursively on the rest of the string
  • Else you have found a brackets that close a nerver opened once, so it is not balanced.

When the string is finally empty, if the list of brackes is empty too (so all the brackes has been closed) return true, else false

ALGORITHM (in Java):

public static boolean isBalanced(final String str1, final LinkedList<Character> openedBrackets, final Map<Character, Character> closeToOpen) {
    if ((str1 == null) || str1.isEmpty()) {
        return openedBrackets.isEmpty();
    } else if (closeToOpen.containsValue(str1.charAt(0))) {
        openedBrackets.add(str1.charAt(0));
        return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
    } else if (closeToOpen.containsKey(str1.charAt(0))) {
        if (openedBrackets.getLast() == closeToOpen.get(str1.charAt(0))) {
            openedBrackets.removeLast();
            return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
        } else {
            return false;
        }
    } else {
        return isBalanced(str1.substring(1), openedBrackets, closeToOpen);
    }
}

TEST:

public static void main(final String[] args) {
    final Map<Character, Character> closeToOpen = new HashMap<Character, Character>();
    closeToOpen.put('}', '{');
    closeToOpen.put(']', '[');
    closeToOpen.put(')', '(');
    closeToOpen.put('>', '<');

    final String[] testSet = new String[] { "abcdefksdhgs", "[{aaa<bb>dd}]<232>", "[ff{<gg}]<ttt>", "{<}>" };
    for (final String test : testSet) {
        System.out.println(test + "  ->  " + isBalanced(test, new LinkedList<Character>(), closeToOpen));
    }
}

OUTPUT:

abcdefksdhgs  ->  true
[{aaa<bb>dd}]<232>  ->  true
[ff{<gg}]<ttt>  ->  false
{<}>  ->  false

Note that i have imported the following classes:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
Luca Mastrostefano
  • 3,201
  • 2
  • 27
  • 34
2
 public static boolean isBalanced(String str) {
    if (str.length() == 0) {
        return true;
    }
    if (str.contains("()")) {
        return isBalanced(str.replaceFirst("\\(\\)", ""));
    }

    if (str.contains("[]")) {
        return isBalanced(str.replaceFirst("\\[\\]", ""));
    }
    if (str.contains("{}")) {
        return isBalanced(str.replaceFirst("\\{\\}", ""));
    } else {
        return false;
    }
}
jot
  • 39
  • 1
2

Balanced Parenthesis (JS)

The more intuitive solution is to use stack like so:

function isBalanced(str) {
  const parentesis = {
    '(': ')',
    '[': ']',
    '{': '}',
  };
  const closing = Object.values(parentesis);
  const stack = [];

  for (let char of str) {
    if (parentesis[char]) {
      stack.push(parentesis[char]);
    } else if (closing.includes(char) && char !== stack.pop()) {
      return false;
    }
  }
 
  return !stack.length;
}

console.log(isBalanced('{[()]}')); // true
console.log(isBalanced('{[(]]}')); // false
console.log(isBalanced('([()]'));  // false

And using recursive function (without using stack), might look something like so:

function isBalanced(str) {
  const parenthesis = {
    '(': ')',
    '[': ']',
    '{': '}',
  };

  if (!str.length) {
    return true;
  }

  for (let i = 0; i < str.length; i++) {
    const char = str[i];

    if (parenthesis[char]) {
      for (let j = str.length - 1; j >= i; j--) {
        const _char = str[j];

        if (parenthesis[_char]) {
          return false;
        } else if (_char === parenthesis[char]) {
          return isBalanced(str.substring(i + 1, j));
        }
      }
    } else if (Object.values(parenthesis).includes(char)) {
      return false;
    }
  }
  return true;
}

console.log(isBalanced('{[()]}')); // true
console.log(isBalanced('{[(]]}')); // false
console.log(isBalanced('([()]'));  // false

* As @Adrian mention, you can also use stack in the recursive function without the need of looking backwards

Community
  • 1
  • 1
Lior Elrom
  • 19,660
  • 16
  • 80
  • 92
1

It doesn't really matter from a logical point of view -- if you keep a stack of all currently un-balanced parens that you pass to each step of the recursion, you'll never need to look backwards, so it doesn't matter if you cut up the string on each recursive call, or just increment an index and only look at the current first character.

In most programming languages, which have non-mutable strings, it's probably more expensive (performance-wise) to shorten the string than it is to pass a slightly larger string on the stack. On the other hand, in a language like C, you could just increment a pointer within the char array. I guess it's pretty language-dependent which of these two approaches is more 'efficient'. They're both equivalent from a conceptual point of view.

Adrian Petrescu
  • 16,629
  • 6
  • 56
  • 82
1

In the Scala programming language, I would do it like this:

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

    def process(chars: List[Char], myStack: Stack[Char]): Boolean =

      if (chars.isEmpty) myStack.isEmpty

      else {
        chars.head match {
          case '(' => process(chars.tail, myStack.push(chars.head))
          case ')' => if (myStack.contains('(')) process(chars.tail, myStack.pop)
          else false
          case '[' => process(chars.tail, myStack.push(chars.head))
          case ']' => {
            if (myStack.contains('[')) process(chars.tail, myStack.pop) else false
          }
          case _ => process(chars.tail, myStack)
        }
      }

    val balancingAuxStack = new Stack[Char]

    process(chars, balancingAuxStack)
  }

Please edit to make it perfect.

I was only suggesting a conversion in Scala.

Unheilig
  • 16,196
  • 193
  • 68
  • 98
MrOnyancha
  • 606
  • 5
  • 28
0

I would say this depends on your design. You could either use two counters or stack with two different symbols or you can handle it using recursion, the difference is in design approach.

Gabriel Ščerbák
  • 18,240
  • 8
  • 37
  • 52
0
func evalExpression(inStringArray:[String])-> Bool{
    var status = false
    var inStringArray = inStringArray
    if inStringArray.count == 0 {
        return true
    }

    // determine the complimentary bracket.
    var complimentaryChar = ""
    if (inStringArray.first == "(" || inStringArray.first == "[" || inStringArray.first == "{"){
        switch inStringArray.first! {
        case "(":
            complimentaryChar = ")"
            break
        case "[":
            complimentaryChar = "]"
            break
        case "{":
            complimentaryChar = "}"
            break
        default:
            break
        }
    }else{
        return false
    }

    // find the complimentary character index in the input array.
    var index = 0
    var subArray = [String]()
    for i in 0..<inStringArray.count{
        if inStringArray[i] == complimentaryChar {
            index = i
        }
    }
    // if no complimetary bracket is found,so return false.
    if index == 0{
        return false
    }
    // create a new sub array for evaluating the brackets.
    for i in 0...index{
        subArray.append(inStringArray[i])
    }

    subArray.removeFirst()
    subArray.removeLast()

    if evalExpression(inStringArray: subArray){
        // if part of the expression evaluates to true continue with the rest.
        for _ in 0...index{
            inStringArray.removeFirst()
        }
        status = evalExpression(inStringArray: inStringArray)
    }

    return status
}
siva k
  • 1
  • 2
0

PHP Solution to check balanced parentheses

<?php
/**
 * @param string $inputString
 */
function isBalanced($inputString)
{
    if (0 == strlen($inputString)) {
        echo 'String length should be greater than 0';
        exit;
    }

    $stack = array();
    for ($i = 0; $i < strlen($inputString); $i++) {
        $char = $inputString[$i];
        if ($char === '(' || $char === '{' || $char === '[') {
            array_push($stack, $char);
        }
        if ($char === ')' || $char === '}' || $char === ']') {
            $matchablePairBraces = array_pop($stack);
            $isMatchingPair = isMatchingPair($char, $matchablePairBraces);
            if (!$isMatchingPair) {
                echo "$inputString is NOT Balanced." . PHP_EOL;
                exit;
            }
        }
    }
    echo "$inputString is Balanced." . PHP_EOL;
}

/**
 * @param string $char1
 * @param string $char2
 * @return bool
 */
function isMatchingPair($char1, $char2)
{
    if ($char1 === ')' && $char2 === '(') {
        return true;
    }
    if ($char1 === '}' && $char2 === '{') {
        return true;
    }
    if ($char1 === ']' && $char2 === '[') {
        return true;
    }
    return false;
}

$inputString = '{ Swatantra (() {} ()) Kumar }';
isBalanced($inputString);
?>
Swatantra Kumar
  • 1,324
  • 5
  • 24
  • 32
-1

It should be a simple use of stack ..

private string tokens = "{([<})]>";        
    Stack<char> stack = new Stack<char>();   

    public bool  IsExpressionVaild(string exp)
    {
        int mid = (tokens.Length / 2)  ;  

        for (int i = 0; i < exp.Length; i++)
        {
            int index = tokens.IndexOf(exp[i]);
            if (-1 == index) { continue; }

            if(index<mid ) stack .Push(exp[i]);
            else 
            {
                if (stack.Pop() != tokens[index - mid]) { return false; }       

            }          

        }
        return true;       

    }
ttk
  • 160
  • 2
  • This is wrong solution! You can't assume first mid will perfect match to other mid! Your solution would work only for (()), ((())), (((())))...and so on...What about ((())()())? It's perfect idea to use Stack but you keep pushing only opening braces and whenever closing brace encounter, you pop from stack. If stack is empty then it's an invalid string. At the end of the string you make sure that stack is empty. If not it's invalid string else valid string. – Paresh Masani Nov 02 '11 at 23:09
-1

@indiv's answer is nice and enough to solve the parentheses grammar problems. If you want to use stack or do not want to use recursive method you can look at the python script on github. It is simple and fast.

BRACKET_ROUND_OPEN = '('
BRACKET_ROUND__CLOSE = ')'
BRACKET_CURLY_OPEN = '{'
BRACKET_CURLY_CLOSE = '}'
BRACKET_SQUARE_OPEN = '['
BRACKET_SQUARE_CLOSE = ']'

TUPLE_OPEN_CLOSE = [(BRACKET_ROUND_OPEN,BRACKET_ROUND__CLOSE),
                    (BRACKET_CURLY_OPEN,BRACKET_CURLY_CLOSE),
                    (BRACKET_SQUARE_OPEN,BRACKET_SQUARE_CLOSE)]
BRACKET_LIST = [BRACKET_ROUND_OPEN,BRACKET_ROUND__CLOSE,BRACKET_CURLY_OPEN,BRACKET_CURLY_CLOSE,BRACKET_SQUARE_OPEN,BRACKET_SQUARE_CLOSE]

def balanced_parentheses(expression):
    stack = list()
    left = expression[0]
    for exp in expression:
        if exp not in BRACKET_LIST:
            continue
        skip = False
        for bracket_couple in TUPLE_OPEN_CLOSE:
            if exp != bracket_couple[0] and exp != bracket_couple[1]:
                continue
            if left == bracket_couple[0] and exp == bracket_couple[1]:
                if len(stack) == 0:
                    return False
                stack.pop()
                skip = True
                left = ''
                if len(stack) > 0:
                    left = stack[len(stack) - 1]
        if not skip:
            left = exp
            stack.append(exp)

    return len(stack) == 0
if __name__ == '__main__':
    print(balanced_parentheses('(()())({})[]'))#True
    print(balanced_parentheses('((balanced)(parentheses))({})[]'))#True
    print(balanced_parentheses('(()())())'))#False
RockOnGom
  • 3,893
  • 6
  • 35
  • 53