What the question is actually asking

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-pointerStack
What it checksSymmetric mirrorCorrect nesting order
Works for palindromes✓unnecessary
Works for nested brackets✗✓
Handles text insidefragilenaturally 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.