Valid Parentheses: Optimal Solution (Data-Backed Guide)

By DSA Prep Team · March 4, 2026 · 8 min read · Algorithms

Valid Parentheses is the #5 most asked LeetCode problem globally — and the canonical introduction to the Stack data structure in interviews.

Our analysis of 10,385 verified interview questions across 259 companies shows this problem appeared 119 times across 48 companies — including Google, Amazon, Meta, Microsoft, Bloomberg, Goldman Sachs, Mastercard, Millennium, LinkedIn, and Intuit.

It looks deceptively simple. But interviewers use it to test three things: whether you immediately reach for a stack, whether you handle all edge cases cleanly, and whether you can extend the solution to harder variants on the fly. This guide covers all three.

Table of Contents

The Data: Why 48 Companies Ask This

MetricValue
Total Interview Appearances119 verified mentions
Companies That Ask It48 companies
Global Rank#5 out of 10,385 questions
DifficultyEasy
Core PatternsStack, String

📌 Companies That Ask This Problem

Google, Amazon, Meta, Microsoft, Bloomberg, Goldman Sachs, Mastercard, Millennium, LinkedIn, Intuit, Adobe, Airbnb, Barclays, BlackRock, Capital One, Cisco, DE Shaw, Disney, Expedia, GE Healthcare, Grab, Huawei, IBM, Infosys, Intel, J.P. Morgan, Morgan Stanley, and 21 more.

Valid Parentheses is asked universally because it is the simplest possible problem that requires a stack. If you solve it with any other approach, you either make it too complex or miss edge cases. Interviewers use it to verify that you understand when and why to use a stack — a skill that transfers directly to harder problems like Largest Rectangle in Histogram, Daily Temperatures, and Decode String.

Problem Statement

LeetCode #20 — Valid Parentheses

Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.
  3. Every close bracket has a corresponding open bracket of the same type.
Examples
Input:  s = "()"        Output: true
Input:  s = "()[]{}"   Output: true
Input:  s = "(]"       Output: false
Input:  s = "([)]"     Output: false  // wrong order
Input:  s = "{[]}"     Output: true   // correctly nested
Input:  s = "("        Output: false  // unclosed bracket
Input:  s = "]"        Output: false  // no matching open

The Core Intuition: Why a Stack?

The key property of valid bracket sequences: the most recently opened bracket must be the first one closed. This is exactly the Last-In-First-Out (LIFO) property of a stack.

Think of it like nested boxes. When you open a box (push to stack), the next thing you close must be that same box (pop from stack and verify match). You can't close an outer box before closing the inner ones.

💡 The Stack Insight in One Sentence

Push every opening bracket onto the stack. When you see a closing bracket, check if the top of the stack is its matching opener. If not — or if the stack is empty — return false. At the end, the stack must be empty.

The Algorithm: Stack-Based Matching

  1. Create an empty stack and a hash map: closing → opening (e.g., ')' → '(').
  2. Iterate through each character in s:
    • If it's an opening bracket ((, [, {) → push to stack.
    • If it's a closing bracket:
      • If stack is empty → return false (nothing to match).
      • Pop the top. If it doesn't match the expected opener → return false.
  3. Return true if stack is empty, false otherwise.

Visual Walkthrough

Tracing s = "{[]}":

StepCharActionStack
1{Opening → push['{']
2[Opening → push['{', '[']
3]Closing → pop '[', matches ✅['{']
4}Closing → pop '{', matches ✅[]
EndStack empty → return true[]

Tracing s = "([)]" — the tricky case:

StepCharActionStack
1(Opening → push['(']
2[Opening → push['(', '[']
3)Closing → pop '[', expected '(' ❌
EndMismatch → return false

Code in Python, Java & JavaScript

Python 3
def isValid(s: str) -> bool:
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}

    for char in s:
        if char in mapping:
            # Closing bracket
            top = stack.pop() if stack else '#'
            if mapping[char] != top:
                return False
        else:
            # Opening bracket
            stack.append(char)

    return not stack  # True if all brackets matched
Java
class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new ArrayDeque<>();
        Map<Character, Character> mapping = new HashMap<>();
        mapping.put(')', '(');
        mapping.put('}', '{');
        mapping.put(']', '[');

        for (char c : s.toCharArray()) {
            if (mapping.containsKey(c)) {
                // Closing bracket
                char top = stack.isEmpty() ? '#' : stack.pop();
                if (mapping.get(c) != top) return false;
            } else {
                // Opening bracket
                stack.push(c);
            }
        }

        return stack.isEmpty();
    }
}
JavaScript
/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    const stack = [];
    const mapping = { ')': '(', '}': '{', ']': '[' };

    for (const char of s) {
        if (mapping[char]) {
            // Closing bracket
            const top = stack.length ? stack.pop() : '#';
            if (mapping[char] !== top) return false;
        } else {
            // Opening bracket
            stack.push(char);
        }
    }

    return stack.length === 0;
};

Complexity Analysis

📊 Complexity Summary

Interview-ready explanation: "Time is O(n) — one pass, constant work per character. Space is O(n) in the worst case when the entire string is opening brackets and nothing has been matched yet."

Edge Cases That Trip People Up

InputExpectedWhy It's Tricky
""trueEmpty string — stack stays empty, return true
")"falseClosing bracket on empty stack
"(("falseStack not empty at end
"([)]"falseCorrect count but wrong nesting order
"{[]}"trueProperly nested mixed brackets
"]"falseSingle unmatched closing bracket

⚠️ The Most Common Interview Mistake

Forgetting to check if the stack is empty before popping when you encounter a closing bracket. Always guard with: top = stack.pop() if stack else '#'. Calling pop on an empty stack throws an exception and will crash your solution.

Stack Problem Family: 6 Must-Know Variants

Valid Parentheses is the entry point to a family of stack problems. Every variant uses the same core push/pop mechanic — just with more complex conditions.

Variant 1: Minimum Remove to Make Valid Parentheses (LC #1249)

"Remove the minimum number of brackets to make the string valid."

Insight: Use a stack to track indices of unmatched opening brackets. After scanning, all indices still in the stack (unmatched opens) plus positions of unmatched closes must be removed.

Variant 2: Longest Valid Parentheses (LC #32)

"Find the length of the longest valid parentheses substring."

Insight: Push indices onto the stack instead of characters. When a match is found, the current valid length is right_index - stack_top_index. Push -1 as a sentinel base.

Python — LC #32 Longest Valid Parentheses
def longestValidParentheses(s):
    stack = [-1]  # sentinel base index
    max_len = 0

    for i, char in enumerate(s):
        if char == '(':
            stack.append(i)
        else:
            stack.pop()
            if not stack:
                stack.append(i)  # new base
            else:
                max_len = max(max_len, i - stack[-1])

    return max_len

Variant 3: Daily Temperatures (LC #739)

"For each day, find how many days until a warmer temperature."

Insight: Monotonic stack — push indices of unresolved days. When a warmer day arrives, pop and calculate the difference.

Python — LC #739 Daily Temperatures
def dailyTemperatures(temperatures):
    result = [0] * len(temperatures)
    stack = []  # indices waiting for a warmer day

    for i, temp in enumerate(temperatures):
        while stack and temperatures[stack[-1]] < temp:
            idx = stack.pop()
            result[idx] = i - idx
        stack.append(i)

    return result

Variant 4: Decode String (LC #394)

"Decode a string like '3[a2[c]]' → 'accaccacc'."

Insight: Two stacks — one for counts, one for strings. Push both when you see [. Pop and combine when you see ].

Variant 5: Largest Rectangle in Histogram (LC #84)

"Find the largest rectangle that fits in a histogram."

Insight: Monotonic increasing stack of bar indices. When a shorter bar is found, pop and calculate area using the current bar as the right boundary.

Variant 6: Score of Parentheses (LC #856)

"Calculate the score where () = 1, AB = A+B, and (A) = 2A."

Insight: Push 0 as a base score on (. On ), pop and either add 1 (if inner was 0) or double the inner score, then add to the new top.

📋 Stack Problem Family — Quick Reference

ProblemStack StoresKey Operation
LC #20 Valid ParensOpening bracketsMatch on close
LC #1249 Min RemoveUnmatched indicesRemove leftover indices
LC #32 Longest ValidIndices (sentinel)Length = i - stack top
LC #739 Daily TempsUnresolved indicesPop when warmer found
LC #394 Decode StringCounts + stringsPop and repeat on ]
LC #84 HistogramBar indicesPop when shorter bar found

When to Recognize the Stack Pattern

💡 Stack vs Recursion

Any recursive solution can be converted to an explicit stack. If a problem has naturally nested subproblems (decode string, evaluate expressions), both work — but an explicit stack avoids call stack overflow on large inputs and is generally preferred in interviews for clarity.

How to Actually Remember This

With 119 appearances across 48 companies including every major FAANG and finance firm, you cannot afford to blank on the stack approach for Valid Parentheses.

✅ Your Spaced Repetition Schedule

  1. Today (Day 0): Solve LC #20 from scratch. Then solve LC #739 (Daily Temperatures) — it introduces the monotonic stack.
  2. Day 3: Solve LC #1249 (Min Remove to Make Valid) and LC #394 (Decode String). Identify what each stack stores.
  3. Day 7: Solve LC #32 (Longest Valid Parentheses). Trace the sentinel index technique on paper.
  4. Day 14: Solve LC #84 (Largest Rectangle in Histogram) — the hardest monotonic stack problem.
  5. Day 30: Pick two random stack problems. Before coding, state what the stack stores and when you push vs pop.

Tag all stack problems on DSAPrep.dev under Stack and Monotonic Stack. The spaced repetition system will resurface them at exactly the right intervals.

Track All Stack Problems on DSAPrep.dev →

One problem at a time. One review at a time. Future you will thank present you.