系列文章目录
前言
真的要每天进步一点点呀!!
一、背景
给出字符串,找到最长有效括号。
来源:力扣
链接: https://leetcode-cn.com/problems/longest-valid-parentheses/
二、我的思路
一开始我的思路很简单,用栈呗,当栈顶元素是‘(’的时候,进来的是‘)’,那么就出栈栈顶元素,一直看最后栈内剩余的元素有多少。我私以为总个数减去剩余个数,便是最后的有效括号数。
但是,我忽略了当串中间有括号未能被匹配的时候,也是会留在栈里面,所以求得的并不是最长有效括号。这也是为什么我加粗了最长的原因。
思来想去,没啥子办法,耗了一晚上。最后看了一点题解,艾,可以用动态规划呀!!!
当有匹配的括号,就在右括号对应的下标进行+2,左括号就默认为前一个值如“(())”。但是这样忽略一个问题,就是这样“()(()”,中间那个左括号等于前一个的值的话,岂不是最后有效长度为4了,这不对。
于是乎,怎么解决呢?不妨让左括号下标对应的数组值为0。但是遇到的情况是:“()()”,这样有效输出是2,这明显不对啊。
于是考虑解决。很明显,左括号下标的数组值必须为0,这是在前面验证过的,那我们可以在匹配到右括号的时候,判断当前配对括号的前一个数组值是否为0,不为零,那么应该加上前面的。
这样就合理了。来操作一下代码:
class Solution {
public:
int longestValidParentheses(string s) {
stack<char> my_stack;
int vec[30000]={0};//栈当数组
int max_i=0;
int i=0;
for(char c:s)
{
if(c=='(') {
my_stack.push(c);
vec[i]=0;//左括号等于0
}
else
{
if (!my_stack.empty()&&my_stack.top()=='(' )
{
my_stack.pop();
if(i>0)
vec[i]=vec[i-1]+2; //有括号且配对,则在前一个加2
if(i-vec[i]>=0&&vec[i-vec[i]]!=0)
vec[i]+=vec[i-vec[i]];
}
else
{
//如右括号不配对
my_stack.push(c);
int mid=-1;
if(i>0)
mid=i-1-vec[i-1];//记录前一个匹配之前的一个下标
else vec[i]=0;
if(mid>=0&&s[mid]=='(') //如果它符合(())这样,加上i前一个i-1的数组值
{
vec[i]=vec[i-1]+2;
//如果是这样()(()),
//那么还要加上(())之前的数值
if(mid-1>=0&&vec[mid-1]!=0)
vec[i]+=vec[mid-1];
}
else vec[i]=0;
}
}
max_i=max(max_i,vec[i]);
i++;
}
return max_i;
}
};
运行通过,唉。
其实最后发现栈其实没必要的,直接用下标操作即可。
三、官方的思路
官方可太强了,三个思路。
1.动态规划
这思路,我是抄它的,它的代码是真的精简啊,直接来代码!!
class Solution {
public:
int longestValidParentheses(string s) {
int maxans = 0, n = s.length();
vector<int> dp(n, 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 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
maxans = max(maxans, dp[i]);
}
}
return maxans;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
2.用栈
这个办法巧妙在于,栈不是用来存放括号,而是用来存放括号的下标。当遇到右括号匹配,出栈,开始计算有效括号长度,最长长度。办法是:用当前下标,减去栈顶元素下标。如果遇到右括号,且栈为空,直接存放右括号下标进去。
这样会有一种情况,刚开始如果没有右括号,这个时候一直来有效括号,那么栈顶就没有元素了呀,这个时候,就统一提前放一个-1的元素,当有孤独的右括号时,把这个-1扔出去即可。
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
int maxans = 0;
stack<int> stk;
stk.push(-1);
for (int i = 0; i < s.length(); i++) {
if (s[i] == '(') {
stk.push(i);
} else {
stk.pop();
if (stk.empty()) {
stk.push(i);
} else {
maxans = max(maxans, i - stk.top());
}
}
}
return maxans;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
3.左右括号记数
这个办法简直太巧妙了,以至于我都不知道怎么想出来的。
同时统计左右括号数量,当数量相等时,开始计算,如果右括号数大于左边,则归0,但是遇到这样的就没办法了:()(()。左右不相等,右也不大于左,那咋办。
从另一边开始遍历试试,同时判断条件也反过来,我去,真的解决了,牛逼!!
代码如下:
class Solution {
public:
int longestValidParentheses(string s) {
int left = 0, right = 0, maxlength = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '(') {
left++;
} else {
right++;
}
if (left == right) {
maxlength = max(maxlength, 2 * right);
} else if (right > left) {
left = right = 0;
}
}
left = right = 0;
for (int i = (int)s.length() - 1; i >= 0; i--) {
if (s[i] == '(') {
left++;
} else {
right++;
}
if (left == right) {
maxlength = max(maxlength, 2 * left);
} else if (left > right) {
left = right = 0;
}
}
return maxlength;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
总结
不懂就别死磕,先看提示,一步步递进,最后再看人家的解决办法!!!
毕竟,很多算法并不是我们想出来的,只要会用就可以了,如果我们对自己没有那么高的要求的话。
喜欢就点个赞叭!