Leetcode–计算一个字符串中最长的有效括号字符长度
首先这又是一道括号匹配的问题,我这里先记录一下之前几道类似的题目:
1、给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
思路:首先空串题目认为是有效字符串,这里只需简单判断,给出结果即可;接下来对于一般字符串,我们利用栈的先进后出结构辅助执行判断:遍历字符串,左符号入左栈,右符号与左栈栈顶进行match判断,如果匹配则左栈pop,否则该右符号push右栈,可能看代码会更清晰些:
bool isValid(string s) {
/*左栈与右栈,左符号入左栈,右符号先与左栈栈顶元素比较,相等左栈顶出栈,否则右栈入栈*/
/*先定义左符号,右符号组*/
if(s.size()==0)
return true;
stack<char> leftStack;
stack<char> rightStack;
for(char& c : s){
if(isLeftSignal(c))
leftStack.push(c);
else if(isRightSignal(c)){
//判断左右栈顶是否相同
if(leftStack.size()==0 || !isMatch(leftStack.top(),c)) return false;
else leftStack.pop();
}
}
if(leftStack.size()==0) return true;
return false;
}
private:
bool isLeftSignal(char c){
if(c == '{' || c == '[' || c =='(')
return true;
else
return false;
}
bool isRightSignal(char c){
if(c == '}' || c == ']' || c ==')')
return true;
else
return false;
}
bool isMatch(char a, char b){
if(a == '(' && b == ')')
return true;
else if(a=='{' && b=='}')
return true;
else if(a=='[' && b==']')
return true;
return false;
}
2、给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
我的一篇博客里有较详细的记录
https://blog.youkuaiyun.com/qq_34606546/article/details/84928073
是回溯法的一种应用
vector<string> generateParenthesis(int n) {
/*回溯,添加时限制条件*/
/*回溯的关键:1、终止条件:当前字符串长度==2*n
2、括号符合规则的条件:(数小于n时可添加(,‘)’同理*/
vector<string> ret;
string str = "";
backTrack(ret, str, 0, 0, n);
return ret;
}
void backTrack(vector<string>& v, string str, int open, int close, int max){
if(str.size() == 2*max){
v.push_back(str);
return;
}
if(open < max)
{
str = str+'(';
backTrack(v, str, open+1, close, max);//第一个一定是'('
str.pop_back();
}
if(close < open) //)的数量一定小于(的数量
{
str = str + ')';
backTrack(v, str, open, close+1, max);
str.pop_back();
}
}
现在来看下这道题:
3、最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 "()()"
leetcode标为了困难,其实倒也没那么难,思路对了还是比较容易的
我们按字符串匹配的思路,首先第一个匹配的一定是 ‘(’,第一个 '('之前的所有 ')'为不匹配部分,不计入匹配个数。在 ‘(‘后,进入一个’(’,计数器加一, ')'计数器减一,遍历字符串的过程中如果计数器为零(完全匹配,记录有效长度),计数器为负(匹配字符结束,计数器清零,重新开始计数)。并注意用max记录最大的有效长度。
int longestValidParentheses(string s) {
if(s.size()==0) return 0;
return calc(s,0,1,s.size());
}
int calc(string s, int i, int flag, int end, char c){
int max = 0, sum = 0, currLen = 0, validLen = 0;
for(; i!=end; i+=flag){
sum += s[i]==c? 1:-1;
currLen++;
if(sum < 0){
max = max>validLen? max:validLen;
sum = 0;
currLen = 0;
}
else if(sum==0){
validLen = currLen;
}
}
return max>validLen ? max:validLen;
}
注意上述思路有一个问题,那就是如果’('较多,如:"(()()(())",无法给出有效长度,计数器sum总是大于零的,所以这里采用反向遍历:
int longestValidParentheses(string s) {
if(s.size()==0) return 0;
return max(calc(s,0,1,s.size(),'('),calc(s,s.size()-1,-1,-1,')'));
}
int calc(string s, int i, int flag, int end, char c){
int max = 0, sum = 0, currLen = 0, validLen = 0;
for(; i!=end; i+=flag){
sum += s[i]==c? 1:-1;
currLen++;
if(sum < 0){
max = max>validLen? max:validLen;
sum = 0;
currLen = 0;
}
else if(sum==0){
validLen = currLen;
}
}
return max>validLen ? max:validLen;
}