LeetCode:32. Longest Valid Parentheses
1.最基本的dp
class Solution {
public:
int longestValidParentheses(string s) {
int sz = s.size();
if (sz == 0)
return 0;
vector<vector<bool>> dp(sz, vector<bool>(sz, false));
int maxLen = 0;
for (int i = sz-1; i >= 0; --i)
for (int j = i; j < sz; ++j) {
if ((j-i+1) & 0x1)
continue;
if (s[i] != '(' || s[j] != ')')
continue;
if (j-i+1 == 2) {
dp[i][j] = true;
} else if (dp[i+1][j-1]) {
dp[i][j] = true;
} else {
for (int k = i+1; k < j; k += 2)
if (dp[i][k] && dp[k+1][j]) {
dp[i][j] = true;
break;
}
}
if (dp[i][j] && (j-i+1) > maxLen)
maxLen = j-i+1;
}
return maxLen;
}
};
//最基本的dp,虽然超时,但是是一个可以用的方法
//思路:
//dp[i][j]:s[i->j]是否有效
//然后首先必须s[i] == '(' && s[j] == ')',然后看大小为2的情况,然后
//1.可能是中间包了有效的括号对,也就是dp[i+1][j-1]
//2.或者分成两段是有效的,也就是那个循环的意思
这个dp是我自己想出来的,但是超时了
2.用栈
class Solution {
public:
int longestValidParentheses(string s) {
int sz = s.size();
if (sz < 2)
return 0;
stack<char> sc;
stack<int> si;
si.push(-1);//方便计算,而且不可或缺,保证了正确性
for (int i = 0; i < sz; ++i) {
if (s[i] == '(') {
sc.push('(');
si.push(i);
} else {
if (sc.empty() || sc.top() != '(') {
sc.push(')');
si.push(i);
} else {
sc.pop();
si.pop();
}
}
}
int maxLen = 0;
int end = sz;
while (!si.empty()) {
int beg = si.top();
si.pop();
int len = end - beg - 1;//len有可能是0, 2, 4。。。
assert(!(len & 0x1));
maxLen = max(maxLen, len);
end = beg;
}
return maxLen;
}
};
//做题过程中暴露出自己的问题:自己检查的时候光注意思路的正确了,没有举出corner case,特殊例子,来攻击自己的算法。检查的时候不仅要注意思路方法的正确,而且需要注意多举几个例子的。
//整体思路:类似用栈来验证括号是否正确的那种题目,这里多用了一个栈来保存相应的index,最后留下的下标,它们两两之间的部分说明是有效的括号组合(连续的有效的都被弹出了,留下的是没办法组合的),那么找出中间部分最长的那一个就是符合题意的
//比如:整个长度为10,最后si中留下了2, 9,那么0->1, 3->8是有效的。
整个思路类似用栈来验证括号是否正确的那一类题目的解法。有一些细节需要注意。这个也是自己写的。
3.dp
class Solution {
public:
int longestValidParentheses(string s) {
int sz = s.size();
if (sz < 2)
return 0;
vector<int> dp(sz, 0);
for (int i = 0; i < sz; ++i) {
if (s[i] == '(')
continue;
if (i > 0 && s[i-1] == '(')
dp[i] = 2 + (i > 1 ? dp[i-2] : 0);
if (i > 0 && s[i-1] == ')') {
if (i-1-dp[i-1] >= 0 && s[i-1-dp[i-1]] == '(')
dp[i] = dp[i-1] + 2 + (i-2-dp[i-1] >= 0? dp[i-2-dp[i-1]] : 0);//重要的一点是:在这种情况下(s[i]==')', s[i-1]==')'),只能这个if所指使的情况下,dp[i]才可能大于0,因为在i-1前面(包括)dp[i-1]个数字中,都是valid的括号对,不可能出现多一个'('来使s[i]的')'消掉
}
}
return *max_element(dp.begin(), dp.end());
}
};
//https://leetcode.com/problems/longest-valid-parentheses/discuss/14133/My-DP-O(n)-solution-without-using-stack
//dp[i]:以s[i]结尾的最长有效子串
//转移方程看链接吧
这个dp方法是看的讨论区来的。确实比我想的dp要简化的多而且效率要高。看来不能脑袋一热就决定状态为二维的,还是需要多试几个。