Problem Statement
You are given a string s that contains only the characters '(', ')', '{', '}', '[', and ']', Your task is to determine whether the string is valid.
A string is considered valid if all of the following hold:
- Open brackets are closed by the same type of bracket.
- They are closed in the correct order.
- Every closing bracket has a corresponding opening bracket.
Return True if s is valid; otherwise, return False.
Constraints:
- $1 \leq$
s.length$\leq 10^{4}$ sconsists of parentheses only ‘()[]{}‘.
Examples
The examples below illustrate a few typical outcomes:
| Input | Output | Explanation |
|---|---|---|
| “{[]}” | True | Each opener is closed by the same type, and closures occur in the correct nesting order. |
| “([{})]” | False | A ) appears while ] is the next expected closer, so the nesting order breaks. |
| “(((())))[]{}” | True | All groups are properly nested and fully closed, leaving no unmatched elements. |
Optimal Solution: Stack-based Validation
The optimal approach is to maintain a stack of the closing brackets we expect to see next, which lets us verify correctness as we scan the string once. Whenever we encounter an opening bracket, we push its matching closing bracket onto the stack, recording what must appear later. When we encounter a closing bracket, it must match the stack’s top; otherwise, the order or type is incorrect, and the string is invalid. A closing bracket with an empty stack is also immediately invalid because there is nothing to match. After processing all characters, the stack must be empty; any remaining expected closers indicate that there are unmatched openings. This avoids any repeated scanning because every character is processed once.
This algorithm is implemented as follows:
- Initialize an empty stack
expected. - Scan characters of
sfrom left to right. - If the character is an opening bracket, push its matching closing bracket onto
expected. - Otherwise (it is a closing bracket):
- If the stack is empty, return
False(nothing to match). - Pop the top element and compare it to the current character; if they differ, return
False.
- If the stack is empty, return
- After the scan ends, return
Trueonly if the stack is empty (no unmatched openers remain).
Here is a visual representation of the algorithm discussed above:
Code Implementation
Time Complexity
The time complexity of this solution is $O(n)$ because each character is pushed to or popped from the stack at most once.
Space Complexity
The space complexity of this solution is $(n)$ because, in the worst case, when the string contains only opening brackets, the stack may hold up to $n$ expected closers.
Common Pitfalls
A few small habits prevent most mistakes on this problem:
- Always guard against popping an empty stack: Any closing bracket that appears when the stack is empty must return
Falseimmediately. - Use a meaningful, consistent stack: Either store opening brackets (and check pairs on close) or store expected closing brackets. Mixing the two leads to subtle bugs.
- Early exits are a feature, not an optimization trick: As soon as a mismatch occurs, the final answer cannot recover; returning immediately keeps the logic clean.
- Quick edge checks help with debugging: Strings of odd length can never be valid, and a valid string must end with an empty stack.