leecode 32. Longest Valid Parentheses
题目大意
给出一个只含有’(‘和’)’的字符串,求这个字符串里面最长的合理括号组合字符串的长度。
解题思路
一开始觉得会跟判断合法括号字符串一样,用一个stack就能解决,但是发现行不通,因为像”()(()”这种情况,没办法将前后的”()”分开。结果只是154 / 229 test cases passed.
代码:
class Solution {
public:
int longestValidParentheses(string s) {
int maxLen = 0, curLen = 0, curInd = 0;
stack<char> parentheseStack;
while (curInd < s.length()) {
if (s[curInd] == '(') {
parentheseStack.push('(');
curInd++;
} else if (s[curInd] == ')' && !parentheseStack.empty() && parentheseStack.top() == '(') {
curLen += 2;
parentheseStack.pop();
curInd++;
} else {
maxLen = max(maxLen, curLen);
curLen = 0;
while (!parentheseStack.empty()) {
parentheseStack.pop();
}
curInd++;
continue;
}
}
maxLen = max(maxLen, curLen);
return maxLen;
}
};
看到一个用stack的O(N)的方法,记录一下
The workflow of the solution is as below.
1. Scan the string from beginning to end.
2. If current character is ‘(‘,push its index to the stack. If current character is ‘)’ and thecharacter at the index of the top of stack is ‘(‘, we just find a matching pair so pop from the stack. Otherwise, we push the index of ‘)’ to the stack.
3. After the scan is done, the stack will only contain the indices of characters which cannot be matched. Then let’s use the opposite side - substring between adjacent indices should be valid parentheses.
4. If the stack is empty, the whole input string is valid. Otherwise, we can scan the stack to get longest valid substring as described in step 3.
改用动态规划,用二维的状态表保存字符串的合法情况,statusTable[i][j]代表的是s[i..j]的合法情况,递推公式比较直观。
代码
const int stringSize = int(s.length());
if (stringSize == 0) {
return 0;
}
bool statusTable[stringSize][stringSize];
for (int i = 1; i < stringSize; i++) {
for (int j = 0; j < stringSize - i; j++) {
if (i == 1) {
statusTable[j][j + i] = s[j] == '(' && s[j + i] == ')';
} else if (i == 2) {
statusTable[j][j + i] = false;
} else {
statusTable[j][j + i] = statusTable[j + 1][j + i - 1] && s[j] == '(' && s[i] == ')';
}
}
}
int maxLen = 0;
for (int i = 1; i < stringSize; i++) {
for (int j = 0; j < stringSize - i; j++) {
if (statusTable[j][j + i]) {
maxLen = max(maxLen, i + 1);
}
}
}
return maxLen;
}
当遇到大小为12477的字符串的时候会runtime error,以为无法在类方法里面分一个大小为12477^2的bool数组。改为动态分配内存。不过仍旧超时,思路太朴素了。
int longestValidParentheses(string s) {
const int stringSize = int(s.length());
if (stringSize == 0) {
return 0;
}
bool **statusTable = new bool*[stringSize];
for (int i = 0; i < stringSize; i++) {
statusTable[i] = new bool[stringSize];
}
for (int i = 1; i < stringSize; i++) {
for (int j = 0; j < stringSize - i; j++) {
if (i == 1) {
statusTable[j][j + i] = s[j] == '(' && s[j + i] == ')';
} else if (i == 2) {
statusTable[j][j + i] = false;
} else {
statusTable[j][j + i] = false;
if (statusTable[j + 1][j + i - 1] && s[j] == '(' && s[j + i] == ')') {
statusTable[j][j + i] = true;
}
for (int k = j + 1; k + 1 < j + i; k++) {
if (statusTable[j][k] && statusTable[k + 1][j + i]) {
statusTable[j][j + i] = true;
break;
}
}
}
}
}
for (int i = 0; i < stringSize; i++) {
for (int j = 0; j < stringSize; j++) {
cout << statusTable[i][j] << " ";
}
cout << endl;
}
cout << endl;
int maxLen = 0;
for (int i = 1; i < stringSize; i++) {
for (int j = 0; j < stringSize - i; j++) {
if (statusTable[j][j + i]) {
maxLen = max(maxLen, i + 1);
}
}
}
return maxLen;
}
换一个思路,直接用一个一维数组statusTable,statusTable[i]就代表是以s[i]为结束字符的字符串的最大合理长度。明显,任何以’(‘为结束的字符串都不可能是合法的,当s[i] == ‘(‘时,statusTable[i]=0;以’)’为结尾的字符串有可能是合法的,如果s[i-1] == ‘(‘,则statusTable[i]=statusTable[i-2]+2;如果s[i-1] == ‘)’,s[i-1]和s[i]就不可能凑成一对,那就要一个个往前推,做比较么,这时候可以利用statusTable[i-1],statusTable[i-1]记录以s[i]为结束字符的字符串的最大合理长度,如果s[i-statusTable[i-1]]==’(‘,就可以得到statusTable[i]=statusTable[i-1]+2,否则就是0。
And the DP idea is :
If s[i] is '(', set longest[i] to 0,because any string end with '(' cannot be a valid one.
Else if s[i] is ')'
If s[i-1] is '(', longest[i] = longest[i-2] + 2
Else if s[i-1] is ')' and s[i-longest[i-1]-1] == '(', longest[i] = longest[i-1] + 2 + longest[i-longest[i-1]-2]
实现代码
class Solution {
public:
int longestValidParentheses(string s) {
const int stringSize = int(s.length());
//用一个一维的数组记录最大长度
if (stringSize == 0) {
return 0;
}
int maxLen = 0;
int statusTable[stringSize];
statusTable[0] = 0;
for (int i = 1; i < stringSize; i++) {
if (s[i] == '(') {
statusTable[i] = 0;
} else {
int internalLen = statusTable[i - 1];
if (s[i - internalLen - 1] == '(') {
if (i - internalLen - 2 >= 0) {
statusTable[i] = statusTable[i - internalLen - 2] + statusTable[i - 1] + 2;
} else {
statusTable[i] = statusTable[i - 1] + 2;
}
maxLen = max(statusTable[i], maxLen);
} else {
statusTable[i] = 0;
}
}
}
for (int i = 0; i < stringSize; i++) {
cout << statusTable[i] << " ";
}
cout << endl;
return maxLen;
}
};