It’s the balanced brackets problem – given a string containing bracket pairs {}, (), [] (with possible text inside), check if every opening bracket has a matching closing bracket in the correct order.
The key insight is nesting order matters:
{()}→ valid,()fully closes before}closes{{(})→ invalid,)tries to close before{is closed — order is broken
Your solution is wrong — it uses a two-pointer (mirror check) approach, which only works for simple palindrome-like patterns. It breaks on nested brackets:
pattern_check("{(})") # your code returns true — WRONG
Because at idx=0: { matches } ✓, at idx=1: ( matches ) ✓ — but the order of closing was never verified.
Correct approach: Stack
def pattern_check(pattern)
matching_opener = {
")" => "(",
"}" => "{",
"]" => "["
}
openers = matching_opener.values # ["(", "{", "["]
stack = []
pattern.each_char do |char|
if openers.include?(char)
stack.push(char)
elsif matching_opener.key?(char) # it's a closer
return false if stack.empty? || stack.last != matching_opener[char]
stack.pop
end
# letters/spaces/anything else → ignored automatically
end
stack.empty?
end
Trace through each example
"{(})" — should return false:
{ → stack: ["{"]( → stack: ["{", "("]} → closer, matching_opener["}"] = "{", stack.last = "(" → "(" != "{" → return false ✓
"{()}" — should return true:
{ → stack: ["{"]( → stack: ["{", "("]) → matching_opener[")"] = "(", stack.last = "(" → match → pop → stack: ["{"]} → matching_opener["}"] = "{", stack.last = "{" → match → pop → stack: []stack.empty? → true ✓
"{( text )}" — should return true:
{ → stack: ["{"]( → stack: ["{", "("]t,e,x,t → not opener or closer → ignored) → match "(" → pop → stack: ["{"]} → match "{" → pop → stack: []stack.empty? → true ✓
Why stack, not two-pointer
| Two-pointer | Stack | |
|---|---|---|
| What it checks | Symmetric mirror | Correct nesting order |
| Works for palindromes | ✓ | unnecessary |
| Works for nested brackets | ✗ | ✓ |
| Handles text inside | fragile | naturally ignored |
The core insight: brackets must close in LIFO order (last opened = first closed) – that’s exactly what a stack models. Every opener goes in, every closer must match the most recent unclosed opener. If it doesn’t → invalid. If the stack is empty at the end → all pairs closed correctly.
This is the same stack solution from your Part 3 Q2 – now you know exactly why stack is the only correct tool for this problem.