Leetcode 32. Longest Valid Parentheses
Find the length of the longest well-formed (balanced) parentheses substring in a string of '(' and ')', handling nested and adjacent valid segments; this typically requires tracking matching positions or lengths (e.g., via a stack, dynamic programming, or a two-pass counter scan) to do efficiently.
DESCRIPTION
Find the length of the longest well-formed (balanced) parentheses substring in a string of '(' and ')', handling nested and adjacent valid segments; this typically requires tracking matching positions or lengths (e.g., via a stack, dynamic programming, or a two-pass counter scan) to do efficiently.
Input:
s = "((()"
Output:
2
Explanation: The longest valid parentheses substring is "()", which has length 2
Constraints:
- 0 <= s.length <= 3 * 10^4
- s[i] is '(' or ')'
- Must find contiguous substring (cannot skip characters)
Understanding the Problem
Let's understand what we're being asked to do. Given a string like '(()', we need to find the length of the longest substring where parentheses are properly balanced.
Tracing through '(()': The substring '()' at the end is balanced (length 2), but the full string is not balanced because there's an extra '(' at the start. So the answer is 2.
For '()(()', we have '()' at the start (length 2) and '()' at the end (length 2), but they're separated by an unmatched '('. The longest single balanced substring is 2.
Important constraint: We need a contiguous substring that is well-formed. We can't skip characters or combine non-adjacent valid segments.
Edge cases to consider: What if the entire string is balanced like '(())'? (return the full length). What if no valid substring exists like '((('? (return 0). What about empty string? (return 0).
Brute Force Approach
The brute force approach checks every possible substring to see if it's balanced. For each starting position, try all ending positions and validate if that substring has matching parentheses. This requires checking if opening and closing counts match and that closing never exceeds opening at any point. While simple to understand, this approach is very inefficient as it examines all possible substrings.
Test Your Knowledge
Login to take the complexity quiz and track your progress
Complexity Analysis
Time Complexity: O(n^3) We have O(n^2) possible substrings, and validating each substring takes O(n) time to check if it's balanced
Space Complexity: O(1) We only use a constant amount of extra space for counters during validation
Building Intuition
A balanced substring has the property that at any point while reading left-to-right, the number of closing parentheses never exceeds the number of opening parentheses.
Additionally, at the end of a valid substring, the counts must be exactly equal. This means we need to track both the positions and the matching relationships.
Simply counting opening and closing parentheses isn't enough because '())()' has equal counts but isn't one valid substring.
We need to know where valid segments start and end. When we encounter a closing ')' that matches an opening '(', we can calculate the length of the valid substring ending at that position.
Think about checking if parentheses match: when you see '(', you're waiting for a future ')' to close it. When you see ')', you need to find its matching '('.
If we track the positions of unmatched opening parentheses, then when we see a closing parenthesis, we can find its match and calculate the length of the valid segment. The challenge is handling nested structures like '((()))' and adjacent segments like '()()'.
Common Mistakes
Only counting opening and closing parentheses without tracking positions - this fails for cases like ')()(' where counts are equal but no valid substring exists
Forgetting to initialize the stack with -1 as a base index - this causes incorrect length calculations for valid substrings starting at index 0
Not handling the case when the stack becomes empty after a pop - this means we found an unmatched closing parenthesis and need to update the base
Confusing 'longest valid substring' with 'longest valid subsequence' - we cannot skip characters, only take contiguous segments
Off-by-one errors when calculating lengths - the length is current_index - stack.top(), not current_index - stack.top() + 1
Optimal Solution
The optimal approach uses a stack to track the indices of unmatched parentheses. We push the index of each '(' onto the stack. When we see ')', we pop from the stack (matching it with the most recent unmatched '('). The key insight is maintaining a base index on the stack to calculate lengths: the current index minus the top of the stack gives us the length of the current valid substring. This efficiently handles both nested structures like '((()))' and adjacent segments like '()()'.
Test Your Knowledge
Login to take the complexity quiz and track your progress
Complexity Analysis
Time Complexity: O(n) We scan through the string once, performing constant-time operations (push/pop) for each character
Space Complexity: O(n) In the worst case (all opening parentheses), the stack stores all n indices
What We've Learned
- Stack for position tracking: Use a stack to store indices (not characters) of parentheses - this allows you to calculate substring lengths by subtracting indices when matches are found, which is essential for finding the longest valid segment rather than just validating balance.
- Base index technique: Initialize the stack with -1 as a base reference point before processing - this handles the edge case where valid parentheses start at index 0, allowing you to calculate length as (current_index - stack.top()) without special conditions.
- Match-and-calculate pattern: When encountering ')', pop the stack first, then check if it's empty - if empty, push current index as new base; if not empty, calculate length from remaining top. This single pattern handles both tracking invalid positions and computing valid lengths.
- Dynamic programming alternative: The DP approach uses dp[i] to store the longest valid length ending at position i - when you find ')', look back at dp[i-1] to skip over the inner valid substring and check if there's a matching '(' before it, then add any valid substring before that match.
- Two-pass counter optimization: Scanning left-to-right tracking open/close counts, then right-to-left achieves O(1) space - reset counters when close > open (or open > close in reverse), and record max when open == close. This works because each pass catches what the other misses in unbalanced scenarios.
- Substring vs subsequence distinction: This problem requires contiguous valid parentheses (substring), not just any valid pairing - that's why we track positions/lengths continuously and reset on invalid characters, rather than just counting matches like in simpler balance-checking problems.
Related Concepts and Problems to Practice
This is the exact same problem as the one being analyzed. It directly practices finding the longest well-formed parentheses substring using stack-based techniques to track matching positions.
This is a foundational problem for parentheses matching using stacks. It teaches the core pattern of using a stack to validate balanced parentheses, which is essential before tackling the longest valid substring variant.
Test Your Understanding
Why is stack the right data structure for this problem?
Select an answer to see the explanation
Question Timeline
See when this question was last asked and where, including any notes left by other candidates.
Mid April, 2026
Mid March, 2026
Late November, 2025
Hello Interview Premium
Your account is free and you can post anonymously if you choose.