Valid Parentheses

Difficulty: Easy

You're given a string made up only of the bracket characters (, ), [, ], {, and }. Figure out whether the brackets are "balanced" — every opening bracket has a matching closing bracket of the same type, and they close in the right order (the most recently opened bracket must be the next one to close).

Examples

Input: s = "()[]{}"
Output: true

Each pair opens and closes cleanly, and none of the pairs overlap improperly.

Input: s = "(]"
Output: false

The opening '(' ends up closed by ']', which is the wrong type of bracket.

Input: s = "([)]"
Output: false

'(' opens, then '[' opens — but ')' shows up before '[' has been closed, closing things out of order.

Constraints

  • 1 <= s.length <= 10^4

  • s consists only of the characters '(', ')', '[', ']', '{', and '}'.

Approach

Because a closing bracket always has to match the most recently opened bracket that hasn't been closed yet, this is naturally a last-in, first-out problem — which is exactly what a stack is for.

Walk through the string one character at a time. Every time you see an opening bracket, push it onto the stack. Every time you see a closing bracket, check it against whatever is on top of the stack: if it matches the type of bracket, pop it off and keep going; if it doesn't match (or the stack is empty when you needed something to match), the string is invalid. At the very end, the string is only valid if the stack is completely empty — otherwise something opened but never closed.

Solutions

Brute Force — Repeatedly Remove Matched Pairs

Repeatedly find and remove any immediately-adjacent matched pair like "()", "[]", or "{}" from the string. If the string collapses all the way down to empty, it was valid. This mimics collapsing the innermost matched pairs one at a time, but it re-scans the string over and over.

function isValid(s) {
  let previous;
  do {
    previous = s;
    s = s.replace("()", "").replace("[]", "").replace("{}", "");
  } while (s !== previous);

  return s.length === 0;
}

Time: O(n²) · Space: O(n)

Optimal — Stack

Push opening brackets onto a stack. When a closing bracket appears, pop the stack and check that it's the matching opening bracket. If it isn't (or there's nothing to pop), the string is invalid right away.

function isValid(s) {
  const stack = [];
  const pairs = { ")": "(", "]": "[", "}": "{" };

  for (const char of s) {
    if (char === "(" || char === "[" || char === "{") {
      stack.push(char);
    } else {
      if (stack.pop() !== pairs[char]) {
        return false;
      }
    }
  }

  return stack.length === 0;
}

Time: O(n) · Space: O(n)