解题思路:
1.获取信息:
给定一个一个只包含'('和')'的字符串,找出最长有效括号子串的长度
2.分析题目:
这让我想到了力扣第20题,那道题是让你判断给定的字符串是不是一个有效的括号字符串
做过那道题的同学应该就知道怎么判断一个字符串有不有效了,那接下来的问题是,怎么选取子串来判断它是否有效呢?
下面的三种方法会给出自己的思路,在这里就不过多地阐述了
3.示例查验:
示例你可以用来检验自己地思路是否正确或者看看自己获取的信息是否有遗漏
示例1:它给我指出了左右扫描法的疏漏
4.尝试编写代码:
1.栈方法
思路:我们之前在力扣第二十题判断是否有效的时候也是使用的栈,这里也是借用那个方法的思路
我们先准备一个栈,先放入一个用来垫底的下标,例如,根本不存在的下标-1,因为下标是从0开始的嘛
接着就从左往右开始扫描,如果遇到左括号就放入栈中,遇到右括号就出栈
遇到右括号时,还要判断栈是否为空
(1)如果为空,说明我们用来垫底的那个下标都出栈了,说明右括号此时已经多于左括号了,已经不可能再构成一个有效的字符串了
我们就将此时的下标作为一个新的垫底下标,重新开始上述不揍即可
(2)不为空,说明才刚刚匹配了一个完整的括号字符串,此时就保存下较长的有效字符串的长度
以下是完整代码
cpp
class Solution {
public:
int longestValidParentheses(string s) {
stack<int>tab;//栈
tab.push(-1);//用来垫底的下标
int res=0;//有效字符串的长度
for(int i=0;i<s.size();i++){
if(s[i]=='(')tab.push(i);//放入下标
else{
tab.pop();//出栈
if(tab.empty())tab.push(i);//为空,则放入新的垫底下标
else res=max(res,i-tab.top());//更新一下最长有效字符串的长度
}
}
return res;
}
};
2.左右扫描法
思路:这道题相较于力扣第20题其实更简单,因为这道题的字符串只有'('和')'两种字符
所以我们可以使用判断左括号和右括号的数目来判断是不是一个有效字符串
我们从左往右扫描,如果遇到左括号就记录下左括号的数目,遇到右括号就记录下右括号的数目
如果左括号的数目等于右括号的数目,就意味着已经形成了一个有效的子串,就记录下这个子串的长度
如果右括号的数目大于左括号,就说明此时的字符串无效,因为就算右边再出现左括号也不可能和右边多的字符串进行匹配闭合了
这样可以找出最长有效的子串长度,但是看到示例1,我发现还是有所缺陷
s = "(()",它无法处理天生的右括号少于左括号的情况
于是,再加上一次从右往左扫描的过程(这个过程要将条件改变一下)就可以解决这个问题
以下是完整代码
cpp
class Solution {
public:
int longestValidParentheses(string s) {
int left=0,right=0;//左括号和右括号的数目
int res=0;
for(int i=0;i<s.size();i++){
if(s[i]=='(')left++;
else if(s[i]==')')right++;
if(right>left){
right=0;left=0;
continue;
}
if(right==left)res=max(res,left+right);
}
left=0;right=0;
for(int i=s.size()-1;i>=0;i--){
if(s[i]==')')right++;
else if(s[i]=='(')left++;
if(left>right){
right=0;left=0;
continue;
}
if(right==left)res=max(res,left+right);
}
return res;
}
};
3.动态规划(源自于力扣题解)
思路:这个方法实在是精妙,如下
有效的子串其中也包含一些有效的子串对吧
动态规划的思想就是,通过小问题来推出大问题
我们要通过最短的有效子串来逐步扩大到较大的有效子串,直到得出一个最大的有效子串
并且,我们也要知道,任意一个有效子串,它结尾的字符一定是一个右括号,所以我们要以右括号来标记一个子串,来推导出它们的关系,看它们是否可以组合成一个更大的有效子串,就是这道题的精髓
先处理最短的有效子串,我们知道最短的有效子串无非就是一个闭合的括号
准备一个和字符串等长的vector来存储各个下标指向的字符能构成的最长的字符串的长度
从左往右扫描,会碰到两种情况
(1)" ( ) "
如果遇到右括号,就看一下它左边的那个字符是不是左括号
如果是,那此时这个右括号的下标存储的最长字符串的长度就是,前面相邻的有效字符串的长度+2,了
如果不是,就无事发生,继续向后扫描
(2)". . . ) ) "
如果遇到右括号,它左边的额那个字符也是右括号
那此时这个右括号的下标存储的长度就取决于它左边那个符号存储的长度和与它匹配的那个括号了
如果没有看懂的话,可以结合我下面的代码来理解,获取去品味一下力扣题解,它还是蛮不错的
cpp
class Solution {
public:
int longestValidParentheses(string s) {
if(s=="")return 0;//如果为空,则返回
int n=s.size();//字符串的大小
vector<int>dp(n,0);//动态规划所需的数组
int res=0;//有效字符串的长度
for(int i=1;i<n;i++){
if(s[i]==')'){
if(s[i-1]=='(')dp[i]=(i>=2?dp[i-2]:0)+2;
else if(i-dp[i-1]>0&&s[i-dp[i-1]-1]=='(')dp[i]=dp[i-1]+((i-dp[i-1]-2>=0)?dp[i-dp[i-1]-2]:0)+2;
res=max(res,dp[i]);
}
}
return res;
}
};
最近天气很热,开空调又过于冷了,不开又被烤化了,难受坏了
希望你能在炎炎夏日中,还能静下心来观看哦
还是要说,纸上得来终觉浅,绝知此事要躬行