Push elements onto the stack; when a closing bracket arrives, pop the top and verify it matches. LIFO guarantees correct nesting order. If the stack is empty on a close or non-empty after scan — invalid.
Each character is pushed at most once and popped at most once — two passes over n chars = O(n) time. In the worst case all opening brackets are pushed before any closing bracket, consuming O(n) space.
({[]}) — scan left to right. Opening brackets ( { [ are pushed onto the stack. Closing brackets ) } ] trigger a pop: if the popped bracket matches the expected closer, continue; otherwise invalid. Stack empty at end = ✅ VALID.
// Simple Stack — Bracket Matching ──────────────────────────────── Deque<Character> stack = new ArrayDeque<>(); for (char c : s.toCharArray()) { if (isOpen(c)) { stack.push(c); // push opening bracket } else { if (stack.isEmpty()) return false; char top = stack.pop(); // pop and verify if (!matches(top, c)) return false; } } return stack.isEmpty(); // leftover = unmatched open