Skip to content

Coding patternsBlind 75

Valid Parentheses

The most recent open bracket must be the first one to close, which is exactly what a stack gives. Solved two ways, removing matched pairs in O(n²) and a stack in O(n), with a step-through, code in five languages and the Big O worked out from the code.

You are given a string text made only of the six bracket characters (, ), [, ], { and }. Return true if every bracket is closed correctly, and false otherwise.

Closed correctly means three things. Every open bracket is closed by the same kind of bracket. Brackets close in the right order: the one opened last closes first. And no closing bracket appears without an open one before it.

Example 1

Input: text = "({[]})()"

Output: true

The square pair sits inside the curly pair, which sits inside the round pair. Then one more round pair follows.

text
(0{1[2]3}4)5(6)7

Example 2

Input: text = "[(])"

Output: false

The “]” arrives while “(” is still open. The brackets cross instead of nesting.

Example 3

Input: text = "(("

Output: false

Both brackets are opened and never closed.

  • 1 ≤ n ≤ 10,000, where n is the length of text
  • text holds only the characters ()[]{}.
Can there be other characters, like letters?
No. Only the six bracket characters.
Is "([])" valid?
Yes. Brackets may nest inside other kinds of brackets.
Is ")(" valid?
No. A closing bracket needs an open one before it, not after.
Does an odd length mean false?
Yes. Every bracket needs a partner, so a valid string has an even length.

Each closing bracket must match the most recent open bracket that is still waiting. “Most recent first” is exactly how a stack works: the last thing you put on top is the first thing you take off. So push every open bracket, and let every closing bracket check the top.

This problem has two approaches. There is no useful step between them.

Stack O(n)

Read the string once, left to right, with a stack.

  • An open bracket goes on top of the stack. It waits there for its partner.
  • A closing bracket must match the bracket on top. If the stack is empty, or the top is a different kind, the string is invalid. If it matches, pop the top: that pair is done.

At the end, the stack must be empty. Anything still on it was opened and never closed.

Why it is correct: the top of the stack is always the most recent open bracket that has not been closed yet, and that is the only bracket a closing bracket is allowed to match.

text
(0{1[2]3}4)5(6)7
stack top →
empty
  1. stack = []
  2. for bracket in text:
  3. if bracket in ")]}":
  4. if not stack or stack[-1] != pair[bracket]:
  5. return False
  6. stack.pop()
  7. else: stack.append(bracket)
  8. return not stack

Read left to right. Push each opening bracket. A closing bracket must match the most recent open one, which is the top of the stack.

1 / 10
Solution.javasolution.pySolution.cssolution.gosolution.ts
class Solution {
// Stack: the latest open bracket must be the first one to close.
// One pass with O(1) work per bracket: O(n) time, O(n) memory.
public boolean isValid(String text) {
Map<Character, Character> pair = Map.of(')', '(', ']', '[', '}', '{');
Deque<Character> stack = new ArrayDeque<>();
for (char bracket : text.toCharArray()) {
if (pair.containsKey(bracket)) {
// A close needs its own kind of open on top, not just any open.
if (stack.isEmpty() || stack.peek() != pair.get(bracket)) return false;
stack.pop();
} else {
stack.push(bracket);
}
}
// Anything left on the stack was opened and never closed.
return stack.isEmpty();
}
}
Time O(n)Space O(n)Here is how we get these from the code, in four steps.
  1. 1 Find the work that repeats

    Each run of the loop does one push, or one check and one pop. A push, a pop and a look at the top each take one step, so each run is 1 step. There is one loop.

    1. stack = []
    2. for bracket in text:
    3. if bracket in ")]}":
    4. if not stack or stack[-1] != pair[bracket]:
    5. return False
    6. stack.pop()
    7. else: stack.append(bracket)
    8. return not stack
  2. 2 Count the runs on Example 1

    Example 1 has 8 characters. The loop runs once for each: 4 pushes and 4 pops.

    8 runs.

    bracket01234567
    char({[]})()
    actionpushpushpushpoppoppoppushpop
  3. 3 Write the count for any n

    n times

    Check it with Example 1: 8 characters, 8 runs.

  4. 4 Keep only the part that grows fastest

    There is nothing to drop. The count is already n.

    So the time is O(n).

  5. S Space: count the extra memory the same way

    In the worst case every character is an open bracket, like “((((”. Then all n go on the stack. The space is O(n).

    stack (up to n brackets)bracket

2,000 random strings of brackets: half balanced, some of those broken by one change, the rest random. The remove pairs and the stack gave the same answer every time.

Largest inputsResult
10,000 brackets (the most allowed): 5,000 opens, then their 5,000 closes, the deepest nesting. Also with the last close the wrong kind. Stack.Under 0.001 s, and about 0.04 MB of extra memory: the stack holds 5,000 brackets, which is the O(n) space.
10,000 brackets, same nesting. Remove pairs.0.06 s for 5,000 passes. Each pass removes only the one pair in the middle.