版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jining11/article/details/82868721
题目要求
Given a string containing just the characters '('
and ')'
, 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 "()()"
思路一:抱着试试看的心态打了分治
class Solution {
public:
bool is_valid(string s) {
//判断是否合法
stack <char> ST;
for (auto c: s) {
if (!ST.empty()&&ST.top() == '(' && c == ')') {
ST.pop();
}
else {
ST.push(c);
}
}
return ST.empty();
}
int longestValidParentheses(string s) {
cout << s << endl;
if (s.size() < 2) {
return 0;
}
int start = 0, end = s.size()-1;
//首先确保以'('开头以')'结束
for (;s[start] == ')' && start <= end; start++);
for (;s[end] == '(' && end >= start; end--);
if (end == start) {
return 0;
}
s = s.substr(start, end-start+1);
if (is_valid(s)) {
return s.size();
}
else {
int m1 = longestValidParentheses(s.substr(1));
int m2 = longestValidParentheses(s.substr(0, s.size()-1));
return max(m1,m2);
}
}
};
运行结果如下:
这是因为分治时会重复讨论某些情况,比如说,‘(()’第一次分治后分别处理'(('和'()',‘((’分治后获得'(','()'分治后会重复'('这一情况。
思路二:抱着这样应该能过的吧的心态打了迭代
充分利用以下特征遍历所有情况:
- 合法序列的长度必定为2
- 合法序列必定以‘(’和‘)’作为开头和结尾
- 其长度必须大于当前查找到的最大长度
class Solution {
public:
bool is_valid(string s) {
//判断是否合法
stack <char> ST;
for (auto c: s) {
if (!ST.empty()&&ST.top() == '(' && c == ')') {
ST.pop();
}
else {
ST.push(c);
}
}
return ST.empty();
}
int longestValidParentheses(string s) {
int start = 0, end = s.size()-1;
//首先确保以'('开头以')'结束
for (;s[start] == ')' && start <= end; start++);
for (;s[end] == '(' && end >= start; end--);
if (end == start) {
return 0;
}
int mmax = 0;
int final = 0;
while (start+mmax <= end+1) {
final = start+max(mmax,2)-1;
while(final <= end) {
if (s[final] == ')' && is_valid(s.substr(start, final-start+1))) {
mmax = final-start+1;
}
final += 2;
}
start++;
for (;s[start] == ')'; start++);
}
return mmax;
}
};
反正这个迭代法我是优化不下去了。。。然鹅离通过测验还是差了几步之遥。
思路三 抱着不会今天都过不了了吧的心态打了动态规划
首先,对于一个长为len的字符串s,维护一个长为len的状态数组dp,其中,dp[i]的含义为s中从i开始且包含i的最长合法序列。
- 初始状态:dp = [0...0]
- 状态转移方程:
- 如果s[i-1]为'('且s[i+dp[i]]为')',那么dp[i-1] = dp[i]+2.如果j = i-1+dp[i-1]没有越界,那么dp[i-1]还要加上dp[j]
- 举个例子:'(())'
- s[3] = '(',s[2] = '(',因此dp[2]、dp[3]依然为0;
- s[1] = '(', s[2+dp[2]]=')',dp[1] = dp[2]+2 = 2, 由于1+dp[1] = 3仍然位于s内部,因此dp[1] = dp[1]+dp[3] = 2;
- s[0] = '(', s[1+dp[1]]=')',dp[0] = dp[1]+2 = 4, 由于0+dp[0] = 4超出s,因此dp[0] = 4;
class Solution {
public:
int longestValidParentheses(string s) {
int start = 0, end = s.size()-1;
//首先确保以'('开头以')'结束
for (;s[start] == ')' && start <= end; start++);
for (;s[end] == '(' && end >= start; end--);
int* dp = new int[s.size()+1]();//多出一位不用判断了
int mmax = 0;
for (int i = end-1; i >= start; i--) {
if (s[i] == '(' && s[i+1+dp[i+1]] == ')') {
dp[i] = dp[i+1]+2+dp[i+2+dp[i+1]];
mmax = mmax > dp[i] ? mmax : dp[i];
}
}
return mmax;
}
};
思路四:抱着原来竟然真的可以这样做的心态打了栈解法
class Solution {
public:
int longestValidParentheses(string s) {
int start = 0, mmax = 0;
stack <int> ST;
//这次栈里面的元素是字符串里面‘(’的索引
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
ST.push(i);
}
else {
if (ST.empty()) {
start = i+1;
}
else {
ST.pop();
mmax = ST.empty() ? max(mmax, i-start+1) : max(mmax, i-ST.top());
}
}
}
return mmax;
}
};