题目来源
题目描述
class Solution {
public:
int longestValidParentheses(string s) {
}
};
题目解析
分析数据量
0 <= s.length <= 3 * 10^4
:O(N * logN)级别的算法s[i] 为 '(' 或 ')'
:不需要检查参数有效性
分析题意
要求返回最长有效的子串的长度
动态规划
像这样的题目都是有套路的。只需要这样思考:
- 必须以0位置结尾而且有效时,往左最长能延伸多长
- 必须以1位置结尾而且有效时,往左最长能延伸多长
- …
即:
- 必须以每个位置结尾的情况下,往左延伸多长有效最长的有效长度
- 每个位置结尾答案如果都能够求出来,整体答案的最大值就是我们想要的
- 因为从客观上来讲,最长有效子串它必须以某个位置结尾,所以所有结尾的最长长度就是我们想要的
问题是,怎么求每个位置的答案
当来到
i
位置时
- 如果
str[i] == (
,不可能以(
结尾,所以dp[i] = 0
- 如果
str[i] == )
,它要被哪些因素影响呢?- 如果
str[i - 1] == (
- 那么
dp[i]
至少为2 - 除此之外,我们还需要看
str[i - 2]
的位置是什么?str[i - 2] = (
,也就是是(()
,那么dp[i] = 2
- 此时
dp[i - 2] = 0
,即dp[i] = 2 + [i - 2]
- 此时
str[i - 2] = )
,此时就要看dp[i - 2]
最远能推多远- 如果
dp[i - 2] = 2
,那么dp[i] = 2 + dp[i - 2] = 4
- 如果
dp[i - 2] = 4
,那么dp[i] = 2 + dp[i - 2] = 6
- 如果
- 综上所述:
str[i - 1] == (
&&str[i] == )
时,以 i i i位置结尾要看 i − 2 i - 2 i−2位置能推多远, d p [ i ] = 2 + d p [ i − 2 ] dp[i] = 2 + dp[i - 2] dp[i]=2+dp[i−2] - 也就是,先看 i i i位置能推多远,然后看i-2位置能推多远
- 那么
- 如果
str[i - 1] == )
- 这个问题和
str[i]
的问题是类似的 - 如果
dp[i - 1] = 0
,那么dp[i] = 0
- 那么
dp[i - 1] = 2
,那么就要看str[i - 3]
是否是(
- 如果不是的话,那么dp[i] = 0
- 如果是的话,那么 d p [ i ] 至少为 d p [ i − 1 ] + 2 dp[i] 至少为 dp[i - 1] + 2 dp[i]至少为dp[i−1]+2,然后还要看pre - 1最远能扩充到哪
- 这个问题和
- 如果
综上:
str[i] == (
时, d p [ i ] = 0 dp[i] = 0 dp[i]=0str[i] == )
时:- 如果
str[i - 1] == (
, d p [ i ] = 2 + d p [ i − 2 ] dp[i] = 2 + dp[i - 2] dp[i]=2+dp[i−2] - 如果
str[i - 1] == )
- 如果 d p [ i − 1 ] = = 0 dp[i - 1] == 0 dp[i−1]==0,那么 d p [ i ] = 0 dp[i] = 0 dp[i]=0
- 如果
d
p
[
i
−
1
]
=
=
k
dp[i - 1] == k
dp[i−1]==k
- 如果str[i - k - 1] ==
)
,那么 d p [ i ] = 0 dp[i] = 0 dp[i]=0 - 如果str[i - k - 1] ==
(
,那么 d p [ i ] = d p [ i − 1 ] + 2 + d p [ ( i − k − 1 ) − 1 ] dp[i] = dp[i - 1] + 2 + dp[(i - k - 1) - 1] dp[i]=dp[i−1]+2+dp[(i−k−1)−1]
- 如果str[i - k - 1] ==
- 如果
class Solution {
public:
int longestValidParentheses(string s) {
if(s.size() < 2){
return 0;
}
// dp[i] : 子串必须以i位置结尾的情况下,往左最远能扩出多长的有效区域
int N = s.size();
std::vector<int> dp(N, 0);
int pre = 0;
int ans = 0;
for (int i = 1; i < N; ++i) {
if(s[i] == ')'){
pre = i - dp[i - 1] - 1; // 与str[i]配对的左括号的位置 pre
if (pre >= 0 && s[pre] == '(') {
dp[i] = dp[i - 1] + 2 + (pre > 0 ? dp[pre - 1] : 0);
}
}
ans = std::max(ans, dp[i]);
}
return ans;
}
};
栈
- 定义start来记录合法括号串的起始位置
- 遍历字符串
- 如果遇到
(
,那么将当前下标入栈 - 如果遇到
)
- 如果栈为空,则将下一个坐标位置记录到start
- 如果栈不为空,则将栈顶元素取出,此时如果栈为空,则更新结果和i-start+1中的较大值;此时若栈为空,则更新结果和 i - start + 1 中的较大值,否则更新结果和 i - st.top() 中的较大值
- 如果遇到
class Solution {
public:
int longestValidParentheses(string s) {
int res = 0, start = 0, n = s.size();
stack<int> st;
for (int i = 0; i < n; ++i) {
if (s[i] == '(') st.push(i);
else if (s[i] == ')') {
if (st.empty()) start = i + 1;
else {
st.pop();
res = st.empty() ? max(res, i - start + 1) : max(res, i - st.top());
}
}
}
return res;
}
};
类似题目
题目 | 描述 |
---|---|
leetcode:32. 最长有效括号 | 栈、动态规划 |
leetcode:22. 给定n,生成所有合法的括号组合 generate-parentheses | |
leetcode:301. 删除无效的括号,得到所有有效的不重复组合 Remove Invalid Parentheses | |
leetcode:20. 有效的括号 Valid Parentheses |