Problem
Problem ID: 32
Title: Longest Valid Parentheses
Difficulty: Hard
Description:
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
Example 1:
Input: s = "(()" Output: 2 Explanation: The longest valid parentheses substring is "()".
Example 2:
Input: s = ")()())" Output: 4 Explanation: The longest valid parentheses substring is "()()".
Example 3:
Input: s = "" Output: 0
Constraints:
0 <= s.length <= 3 * 104
s[i]
is'('
, or')'
.
Thoughts
This is hard problem that requires strong observation skills. I re-did this problem a couple times but always have trouble realising the key observations.
Solution | DP
General Idea
The longest parentheses can either consist of a single component parentheses (cannot be split into two
component of valid parentheses) or two component parentheses. Thus, the longest single
valid parentheses is trying to get the longest single component parentheses ending at i
and combining it with any adjacent single component parentheses.
Implementation
DP State:
dp[i]
: represents the length of longest valid parentheses ending ats[i]
- All entries initialize to
0
DP transition:
- Longest single component:
dp[i] += dp[i-1] + 2
ifs[i] == ')'
ands[i-dp[i-1] -1] == '('
- Try to wrap the valid parentheses ending at
i-1
with(
and)
(ati
)
- Try to wrap the valid parentheses ending at
- Concat adjacent valid parentheses
dp[i] += (dp[i - dp[i-1] - 2])
- Try to concat the valid parentheses with the newly found longest single component
class Solution {
public:
int longestValidParentheses(string s) {
auto n = s.size();
// dp[i] = longest paran ending at char i
vector<size_t> dp(n, 0);
auto print = [&] { for (auto num : dp) cout << num << " "; };
size_t ret = 0;
for (size_t r = 0; r < n; r++) {
size_t l = r-1;
if (r > 0) l = r - dp[r-1] - 1;
if (l >= n) continue;
if (!(s[l] == '(' && s[r] == ')')) continue;
dp[r] = (r - l + 1);
if (l > 0) dp[r] += dp[l-1];
ret = max(ret, dp[r]);
}
print();
return ret;
}
};
Solution | Stack
General Idea
Observation: Even though the entire string might not be a valid parentheses, performing the normal parentheses matching algorithm will match any valid parentheses substring.
Implementation
Algorithm:
- Perform the normal parentheses matching algorithm with a stack
- At the end of each iteration, the top element in the stack represents an unmatched
parentheses
- The substring between the top element of stack (non-inclusive) and the current element (inclusive) is a valid parentheses
- We will just need to max on this substring length to get the answer.
class Solution {
public:
int longestValidParentheses(string s) {
auto n = s.size();
// dp[i] = longest paran ending at char i
vector<size_t> dp(n, 0);
auto print = [&] { for (auto num : dp) cout << num << " "; };
size_t ret = 0;
for (size_t r = 0; r < n; r++) {
size_t l = r-1;
if (r > 0) l = r - dp[r-1] - 1;
if (l >= n) continue;
if (!(s[l] == '(' && s[r] == ')')) continue;
dp[r] = (r - l + 1);
if (l > 0) dp[r] += dp[l-1];
ret = max(ret, dp[r]);
}
print();
return ret;
}
};