32. Longest Valid Parentheses - Detailed Explanation
Problem Statement
You are given a string containing just the characters '('
and ')'
. Your task is to find the length of the longest valid (well-formed) parentheses substring.
Example 1
- Input:
"(()"
- Output:
2
- Explanation: The longest valid parentheses substring is
"()"
.
Example 2
- Input:
")()())"
- Output:
4
- Explanation: The longest valid parentheses substring is
"()()"
.
Example 3
- Input:
""
- Output:
0
- Explanation: The string is empty, so there is no valid substring.
Constraints:
- The length of the string is between
0
and a large number (e.g.,30000
). - The string consists only of the characters
'('
and')'
.
Hints
-
Stack Hint:
Think about using a stack to store indices. This can help you determine the start of a valid substring when you encounter a closing parenthesis. -
Dynamic Programming Hint:
Consider using a DP array where each element represents the length of the longest valid substring ending at that index. Update this array based on previous computations.
Approaches
Brute Force Approach
-
Idea:
Check every possible substring and verify if it is valid by using a stack or a counter. -
Steps:
- Generate all possible substrings.
- For each substring, check if it forms a valid parentheses sequence.
- Keep track of the maximum valid length found.
-
Complexity:
- Time: O(n³) (O(n²) substrings and O(n) to validate each)
- Space: O(n) for validation checks
Not efficient for large inputs.
Dynamic Programming Approach
-
Idea:
Use a DP array wheredp[i]
represents the length of the longest valid substring ending at indexi
. -
Steps:
- Initialize a DP array of zeros.
- Iterate through the string from index
1
to the end. - If
s[i]
is')'
:- If
s[i-1]
is'('
, then update:
dp[i] = (dp[i-2] if i >= 2 else 0) + 2
- Else if
s[i-1]
is')'
and the character before the previous valid substring (at indexi-dp[i-1]-1
) is'('
, update:
dp[i] = dp[i-1] + 2 + (dp[i-dp[i-1]-2] if (i-dp[i-1]) >= 2 else 0)
- If
- Update the maximum length encountered.
-
Complexity:
- Time: O(n)
- Space: O(n)
Stack-Based Approach
-
Idea:
Use a stack to keep track of indices. Push-1
initially to handle edge cases. -
Steps:
- Initialize a stack with
-1
. - Iterate through the string:
- If the character is
'('
, push its index onto the stack. - If the character is
')'
, pop the top of the stack.- If the stack is empty after popping, push the current index.
- Else, update the maximum valid length using:
current_length = current_index - stack.top()
- If the character is
- The maximum value encountered during the iteration is the answer.
- Initialize a stack with
-
Complexity:
- Time: O(n)
- Space: O(n)
Two-Pass / Counter Approach
-
Idea:
Use two counters (for left and right parentheses) and scan the string twice—once from left to right and once from right to left. -
Steps (Left-to-Right):
- Initialize
left = 0
andright = 0
. - For each character:
- Increment
left
if the character is'('
. - Increment
right
if the character is')'
. - If
left == right
, update the maximum length. - If
right > left
, reset both counters.
- Increment
- Initialize
-
Steps (Right-to-Left):
- Reset
left = 0
andright = 0
. - Iterate from the end of the string:
- Increment counters similarly.
- If
left == right
, update the maximum length. - If
left > right
, reset both counters.
- Reset
-
Complexity:
- Time: O(n)
- Space: O(1)
Complexity Analysis
-
Brute Force:
- Time: O(n³)
- Space: O(n)
-
Dynamic Programming:
- Time: O(n)
- Space: O(n)
-
Stack-Based:
- Time: O(n)
- Space: O(n)
-
Two-Pass / Counter:
- Time: O(n)
- Space: O(1)
Python Code
Java Code
Step-by-Step Walkthrough and Visual Examples
Visual Example (Stack-Based Approach)
For the input ")()())"
:
-
Initialization:
- Stack:
[-1]
(used to handle edge cases)
- Stack:
-
Iteration:
-
Index 0:
- Character:
')'
- Stack before:
[-1]
- Pop the top (since it's a closing parenthesis) → Stack becomes empty
- Since the stack is empty, push current index
0
- Stack now:
[0]
- Character:
-
Index 1:
- Character:
'('
- Push index
1
- Stack now:
[0, 1]
- Character:
-
Index 2:
- Character:
')'
- Pop index
1
- Stack now:
[0]
- Valid length:
2 - 0 = 2
→ Update max length to2
- Character:
-
Index 3:
- Character:
'('
- Push index
3
- Stack now:
[0, 3]
- Character:
-
Index 4:
- Character:
')'
- Pop index
3
- Stack now:
[0]
- Valid length:
4 - 0 = 4
→ Update max length to4
- Character:
-
Index 5:
- Character:
')'
- Pop from stack → Stack becomes empty
- Since the stack is empty, push current index
5
- Stack now:
[5]
- Character:
-
-
Result:
- Maximum valid length is
4
.
- Maximum valid length is
Common Mistakes
-
Ignoring Edge Cases:
Not handling empty strings or strings with only one type of parenthesis. -
Stack Initialization:
Forgetting to initialize the stack with-1
in the stack-based approach, which is crucial for calculating lengths correctly. -
DP Array Updates:
Incorrectly updating the DP array when a previous valid substring exists, leading to off-by-one errors.
Edge Cases
-
Empty String:
The string""
should return0
. -
All Opening or All Closing:
E.g.,"((("
or")))"
should return0
. -
Entirely Valid String:
A string like"()()()"
should return its full length. -
Alternating Patterns:
Strings with alternating patterns that might trick simple counters if not handled correctly.
Alternative Variations
-
Return the Substring:
Instead of just returning the length, modify the problem to return the longest valid parentheses substring itself. -
Multiple Types of Brackets:
Extend the problem to handle multiple types of brackets such as'{'
,'}'
,'['
,']'
in addition to'('
and')'
.
Related Problems
-
Valid Parentheses (Leetcode 20):
Check if a given string of parentheses is valid. -
Minimum Remove to Make Valid Parentheses (Leetcode 1249):
Remove the minimum number of characters to make the parentheses string valid.
GET YOUR FREE
Coding Questions Catalog