Longest Valid Parentheses

HardStack · Two-Pass Counting🧩 StackLeetCode #32 ↗Updated

Problem

A string s contains only '(' and ')'. Return the length of the longest contiguous substring that is a well-formed (balanced and properly nested) parentheses sequence. Return 0 if none exists.
Input")()())"Output4 ("()()")
Input"(()"Output2
Input""Output0

0 ≤ s.length ≤ 3·104  ·  s[i] is '(' or ')'

Try it yourself

Java
class Solution {
    public int longestValidParentheses(String s) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
An unmatched ')' acts as a wall: no valid substring can cross it. Track the last wall (stack of indices) — or just count opens/closes and reset at each wall.
PatternStack

Instinct Things resolve in reverse order of arrival (brackets, adjacent pairs, nested expressions) - push now, pop when its partner shows up.

Memory hack Last in, first out - like a pile of plates, you only ever touch the one on top; every closer pops its opener.

Open the Stack guide →

Approaches

Brute ForceCheck Every Even-Length Substring

Time O(n3)Space O(1)

For every start i and every even end j, scan s[i..j) with a balance counter: it must never go negative and must end at 0. Keep the longest valid length.

Java
public int longestValidParentheses(String s) {
    int maxLen = 0;
    for (int i = 0; i < s.length(); i++) {
        for (int j = i + 2; j <= s.length(); j += 2) {   // even lengths only
            if (isValid(s, i, j)) maxLen = Math.max(maxLen, j - i);
        }
    }
    return maxLen;
}

private boolean isValid(String s, int from, int to) {
    int balance = 0;
    for (int k = from; k < to; k++) {
        balance += s.charAt(k) == '(' ? 1 : -1;
        if (balance < 0) return false;                  // more ')' than '('
    }
    return balance == 0;
}

Obviously correct, but cubic — hopeless at n = 3·104.

At a glance

LevelApproachTimeSpace
Brute ForceCheck Every Even-Length SubstringO(n3)O(1)
BetterStack of IndicesO(n)O(n)
OptimalTwo-Pass Open/Close CountersO(n)O(1)
Common pitfalls
  • Counting only total balance — ")(" is balanced but not valid.
  • Doing only the left→right pass — "(()" returns 0 instead of 2.
  • Forgetting the -1 sentinel — runs starting at index 0 are mis-measured.
Interview tips
  • Clarify: substring (contiguous), not subsequence.
  • Explain the stack bottom as “index just before the current valid run”.
  • Show the "(()" counter-example to justify the second pass.
Pattern
Stack of indices / balance counters → longest contiguous well-formed bracket segment.
My notes saved in this browser