21. Valid Parentheses
View on NeetCode
View on LeetCode
Problem
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
An input string is valid if:
- Open brackets must be closed by the same type of brackets.
- Open brackets must be closed in the correct order.
- Every close bracket has a corresponding open bracket of the same type.
Example 1:
Input: s = "()"
Output: true
Example 2:
Input: s = "()[]{}"
Output: true
Example 3:
Input: s = "(]"
Output: false
Constraints:
1 <= s.length <= 10^4sconsists of parentheses only'()[]{}'.
Solution
Approach: Stack
The key insight is to use a stack to track opening brackets. When we encounter a closing bracket, it must match the most recent unmatched opening bracket (the top of the stack).
Algorithm:
- Push opening brackets onto the stack
- For closing brackets, check if they match the top of the stack
- If they match, pop the stack; otherwise, return false
- At the end, the stack should be empty
Implementation
class Solution:
def isValid(self, s: str) -> bool:
stack = []
# Mapping of closing to opening brackets
matching = {')': '(', '}': '{', ']': '['}
for char in s:
if char in matching:
# Closing bracket
if not stack or stack[-1] != matching[char]:
return False
stack.pop()
else:
# Opening bracket
stack.append(char)
# Valid only if all brackets are matched
return len(stack) == 0
Alternative (Using Dictionary for Opening Brackets):
class Solution:
def isValid(self, s: str) -> bool:
stack = []
closing_to_opening = {')': '(', '}': '{', ']': '['}
opening = set(['(', '{', '['])
for char in s:
if char in opening:
stack.append(char)
elif char in closing_to_opening:
if not stack or stack.pop() != closing_to_opening[char]:
return False
return not stack
Complexity Analysis
- Time Complexity: O(n), where n is the length of the string. We process each character once.
- Space Complexity: O(n) in the worst case, when all characters are opening brackets and we push them all onto the stack.
Key Insights
-
Stack for LIFO Matching: A stack is perfect for this problem because the most recent unmatched opening bracket must match the current closing bracket (Last-In-First-Out).
-
Early Termination: If we encounter a closing bracket without a matching opening bracket on the stack, we can immediately return false.
-
Complete Matching: After processing all characters, the stack must be empty. A non-empty stack means there are unmatched opening brackets.
-
Three Failure Cases:
- Closing bracket without matching opening (empty stack or wrong type)
- Extra opening brackets (non-empty stack at end)
- Wrong order (closing bracket doesn’t match top of stack)