32. Longest Valid Parentheses¶
Edited by Charles
Hard · Python · Dynamic Programming
Problem
Read the original problem on LeetCode.
The official page contains the problem statement, examples, and constraints.
Explanation, examples & other approaches
Core idea
Given a string s containing only:
return the length of the longest valid parentheses substring.
Original study notes follow, including intermediate snippets and earlier attempts.
Problem¶
Given a string s containing only:
return the length of the longest valid parentheses substring.
Example¶
Because the longest valid parentheses substring is:
with length:
The most important part of this problem is the definition of dp[i].
Define:
The key phrase is:
It does not mean:
Consider:
At index 4:
There is a valid substring of length 4 ending at index 4.
Therefore:
But at index 5:
there is no valid parentheses substring ending at index 5.
Therefore:
So:
even though the answer is 4.
Therefore, the final answer is:
rather than:
A valid parentheses substring must end with:
It cannot end with:
Therefore, if:
then:
We only need to process positions where:
Suppose:
That is:
Then:
which gives us a new valid pair of length 2.
But there may already be a valid parentheses substring immediately before this pair.
For example:
At the last ):
The current:
contributes:
and the previous valid substring contributes:
Therefore:
If i < 2, there is nothing before the current ().
So we write:
Now consider:
We cannot directly match:
However, dp[i-1] may tell us that there is already a valid parentheses substring ending at i-1.
For example:
At the final ):
We already know:
because:
ends at index 2.
Graphically:
We want to find the character immediately before the valid substring ending at i-1.
The valid substring ending at i-1 has length:
So we jump backward by that many characters and then one additional position:
This j represents:
The position that might contain the
(matching the currents[i] == ')'.
For:
we have:
So:
Now:
so s[j] can match the current s[i].
If:
then we can combine:
The existing valid substring has length:
The new outer pair contributes:
Therefore:
But there is one more important case.
Consider:
The final (()) is valid, but there is also another valid substring before it:
We want to combine them into:
So after finding j, we also need to check whether there is another valid substring ending at:
Therefore:
If j == 0, then there is nothing before j.
So:
Consider:
The current structure is:
The part:
gives:
But there may also be another valid substring immediately before the matching (.
That substring ends at:
Its length is:
Therefore:
dp[i]
=
previous valid substring
+
current inner valid substring
+
new pair
=
dp[j - 1]
+
dp[i - 1]
+
2
The entire problem can be summarized into two cases.
Case 1¶
If:
then:
Case 2¶
If:
first find:
If:
then:
where dp[j - 1] is included only when:
s[i] == ')'
│
├── Case 1: s[i-1] == '('
│
│ ... ( )
│ ↑ ↑
│ i-1 i
│
│ dp[i]
│ = dp[i-2] + 2
│
│
└── Case 2: s[i-1] == ')'
... ( [valid] )
↑ ↑
j i
j = i - dp[i-1] - 1
if s[j] == '(':
dp[i]
= dp[i-1] + 2 + dp[j-1]
Consider:
Initially:
i = 1¶
A valid parentheses substring cannot end with (.
Therefore:
i = 2¶
This is Case 1:
Therefore:
Now:
i = 3¶
Therefore:
i = 4¶
Again, Case 1:
Now:
The valid substring ending at index 4 is:
i = 5¶
This is Case 2.
Calculate:
So:
But:
not:
Therefore, the current ) cannot form a valid substring ending at index 5.
So:
Final DP array:
Therefore:
This is an important detail.
Our definition is:
Therefore:
only tells us the longest valid substring that ends at the last character.
It does not represent the maximum over the entire string.
For:
we have:
So:
but:
Therefore, the answer is:
or we can maintain a global maximum:
Time Complexity¶
We traverse the string once:
Space Complexity¶
We use a DP array of length n:
The most important definition is:
Therefore:
When:
there are two cases:
and:
If:
then:
Finally, remember:
so the final answer is:
not:
Study record
| Field | Value |
|---|---|
| Attempts | 1 |
| Mastery | ❚ |
| The Latest Attempt | September 17, 2026 |
Python solution¶
class Solution:
def longestValidParentheses(self, s: str) -> int:
n = len(s)
if n == 0:
return 0
dp = [0] * n
res = 0
for i in range(1, n):
if s[i] == ')':
# Case 1: ...()
if s[i - 1] == '(':
dp[i] = (dp[i - 2] if i >= 2 else 0) + 2
# Case 2: ...))
else:
j = i - dp[i - 1] - 1
if j >= 0 and s[j] == '(':
# Case (())
dp[i] = dp[i - 1] + 2
if j >= 1:
# Case ()(())
dp[i] += dp[j - 1]
res = max(res, dp[i])
return res