Code Corner: Bracket Balancing

java interview balancing brackets

java interview balancing brackets

Given a sentence or formula containing square brackets, curly braces and brackets, write an algorithm to determine if it is balanced.

This question has been around for a long time but often candidates can struggle with it due to having limited data structures experience.  There’s a number of possible ways of coming up with a solution, but here’s the best I’m aware of.

At its purest form this is a matching exercise. We obviously need to loop through the characters in the sentence.  For efficiency we want to only iterate through it once, which rules out the option of taking each character and then trying to find it’s partner from the opposite end (which will result in multiple iterations).  But how do we keep track of what we have seen, and in what order?

In day to day work, people generally spend most of their time with Lists and Maps.  There’s a ton of other collections in the Java universe but people don’t get experience with them which is why this can be so tricky.   The data structure we’re looking for here is a Stack.  Stacks are LIFO, Last In First Out.  That means whichever element I most recently added will be removed first.  This is perfect for this exercise, as it means as I go through I can pop opening brackets onto the Stack, and if I find a closing brace I then can compare it to whatever is on top of the stack. If it matches then we’re happy, else we know we’re unbalanced.

//pseudocode
loop through characters of string 
   If(this character is an opening brace)
      push onto stack
   if(this character is a closing brace)
      pop from stack. If it isn't the matching brace, return false

If you had figured out this far then well done.  You know how to use Stacks and how to apply it to this problem which is the main test as part of this question.  There are a couple of hazards to avoid when implementing though.

Firstly, although Java does have a Stack collection you shouldn’t use it. Even Oracle’s own documentation says to avoid it in favour of Dequeue.  A Dequeue is a double ended queue and has functionality to support LIFO and FIFO (First in First Out) functionality.

Secondly, it’s really easy to write ugly code for this.  Most the implementations you’ll find on line have a ton of if statements; there’s a particularly horrible implantation from Princeton you can see the source for here.  Big if statements are a terrible practice; they’re very difficult to read and understand.  Your code combined with your tests should be your documentation; if you feel the need to write comments then 95% of the time you need to break your code down and make it simpler. Hopefully you can apply your knowledge to come up with something a bit more obvious!

import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class StackFormulaBalanceTest {

    private StackFormulaBalance stackFormulaBalance;

    @Test
    public void emptyStringIsBalanced() throws Exception {
        stackFormulaBalance = new StackFormulaBalance();
        assertThat(stackFormulaBalance.balance(""), is(true));
    }

    @Test
    public void lotsOfNestedBracketsButBalancedReturnsTrue() throws Exception {
        stackFormulaBalance = new StackFormulaBalance();
        assertThat(stackFormulaBalance.balance("([Hell{} T(h(e[r]e))]boom)"), is(true));
    }
    @Test
    public void correctNumberOfClosingBracketsButInWrongOrderReturnsFalse() throws Exception {
        stackFormulaBalance = new StackFormulaBalance();
        assertThat(stackFormulaBalance.balance("(a[b{c)d]e}"), is(false));
    }
    @Test
    public void onlyHasClosedBracesReturnsFalse() throws Exception {
        stackFormulaBalance = new StackFormulaBalance();
        assertThat(stackFormulaBalance.balance("}])"), is(false));
    }
    @Test
    public void correctBalancingButWithMoreOpeningBracketsReturnsFalse() throws Exception {
    stackFormulaBalance = new StackFormulaBalance();
    assertThat(stackFormulaBalance.balance("({}"), is(false));
    }
}


import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;

public class StackFormulaBalance {
    Map<Character, Character> brackets = new HashMap<Character, Character>() {{
        put('{', '}');
        put('(', ')');
        put('[', ']');
    }};

    public boolean balance(String toBalance) {
        Deque<Character> bracketsStack = new ArrayDeque<Character>();
        for (int i = 0; i < toBalance.length(); i++) {
            char currentChar = toBalance.charAt(i);
            if (characterIsOpenBracket(currentChar)) {
                bracketsStack.push(currentChar);
            } else if (characterIsAClosingBracket(currentChar) &&
                    closingBracketMatchesLastOpeningBracket(bracketsStack, currentChar)) {
                return false;
            }
        }
        return bracketsStack.isEmpty;
    }

    private boolean closingBracketMatchesLastOpeningBracket(Deque<Character> bracketsStack, char currentChar) {
        return bracketsStack.size() == 0 || !brackets.get(bracketsStack.pop()).equals(currentChar);
    }

    private boolean characterIsAClosingBracket(char currentChar) {
        return brackets.values().contains(currentChar);
    }

    private boolean characterIsOpenBracket(char currentChar) {
        return brackets.containsKey(currentChar);
    }
}

The private methods could be inlined if you’re that way inclined, but by pulling them out and naming them well we can make our algorithm clear. It reads very similarly to the pseudocode.

What do you think? Do you have a better implementation or other suggestions? Let me know!

9 Comments

  • […] Ich kann mir nicht helfen, nach zwei Jahren Ruby sieht Java manchmal nur noch umständlich aus. Gerade bei kleinen, in sich geschlossenen Programmen sollte man die Sprache mit Bedacht wählen. Wie aufwendig kann es sein herauszufinden, ob die verschiedenen Klammerarten in einem String ausbalanciert sind? Diese Frage stellte sich auch Code Corner und lieferte diese Lösung in Java: […]

  • I didn’t really test it but I think your example fails to check “(“. You have to ensure that the stack is empty rather than returning true. However, nice exercise. I blogged about my Ruby implementation (German, but its all about the code, right?): http://sgaul.de/2014/11/29/bracket-balancing-in-ruby/

    • Seb! You were completely correct. I’ve updated the post with an extra test and fixed the return to check the stack is empty.
      Thanks for your post on the Ruby version, google translate helped me out quite a bit. There’s definitely bits in there that look much nicer (the map definition for starts), although I’m not sure I’m a fan of the “BRACKETS.keys.include? char” type syntax. Probably need to play in Ruby for a bit :)

      • Totally agree with you, this “BRACKETS.keys.include? char” was the shortest approach that came to my mind, not the most beautiful ;)

  • This code does so much useless crap to do a simple task: Check for balancing for some open and closing characters. No need to waste time and memory by creating stacks and array dequeues. How about this simple algorithm…

    private static boolean isBalanced(String s, char open, char close) {
    int q = 0;
    for (char p : s.toCharArray()) {
    if (p == open) q++;
    if (p == close) q–;
    if (q < 0) return false;
    }
    return true;
    }

    public static boolean isBalanced(String s, Map map) {
    for (Map.Entry k : map.entrySet())
    if (!isBalanced(s, k.getKey(), k.getValue()))
    return false;
    return true;
    }

    and it can be called with

    Map map = new TreeMap();
    map.put(‘{‘, ‘}’);
    map.put(‘[‘, ‘]’);
    map.put(‘(‘, ‘)’);
    System.out.println(isBalanced(“{{[hello, (( glorious ) world})]”, map));

  • check: [ ( ] )

    • Added it as a test on my machine and it correctly passed:
      @Test
      public void comment() throws Exception {
      stackFormulaBalance = new StackFormulaBalance();
      assertThat(stackFormulaBalance.balance(“[ ( ] )”), is(false));
      }

  • I think the method closingBracketMatchesLastOpeningBracket should be renamed to closingBracketNotMatchesLastOpeningBracket

  • Hi Sam,
    1. For the brackets you use Double Brace Initialisation. There are some implication of this. http://c2.com/cgi/wiki?DoubleBraceInitialization.

    2. It’s not good idea to modify parameter inside a method. See closingBracketMatchesLastOpeningBracket

    3. There are 3 ways to loop through a String
    #1. charAt. The problem is that every time the index is checked.
    public char charAt(int index) {
    if ((index = value.length)) {
    throw new StringIndexOutOfBoundsException(index);
    }
    return value[index];
    }
    #2. String.toCharArray better readability.for each loop
    #3. Use reflection to access the array of chars inside the String and therefore improve performance. More ugly but faster….

    4. Autoboxing is everywhere… Do you have any idea how this could be improved??

    5. My solution:
    public class Validator {

    private static final Map brackets= new HashMap();
    static{
    brackets.put(‘{‘, ‘}’);
    brackets.put(‘[‘, ‘]’);
    brackets.put(‘(‘, ‘)’);
    }

    public static boolean validate(String input) {
    Stack stack = new Stack();
    for(char c:input.toCharArray()){
    if(isOpening(c)){
    stack.push(c);
    }else if(isClosing(c)){
    if(stack.isEmpty() || !match(stack.pop().charValue(), c)){
    return false;
    }
    }
    }
    return stack.isEmpty();
    }

    private static boolean isOpening(char c){
    return brackets.containsKey(c);
    }

    private static boolean isClosing(char c){
    return brackets.containsValue(c);
    }

    private static boolean match(char opening, char closing){
    return brackets.get(opening)==closing;
    }
    }

Join the Discussion

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>