给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:
输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
来源:力扣(LeetCode)
这一题真的太有意思了,栈,动态规划,还有括号计数,都是很方便很巧妙的方法,但我只会最low的暴力求每个子串的最大长度,哈哈😭
(一)
先说说括号计数的方法吧,顾名思义就是计数左右括号出现的次数
这种方法需要两次遍历,一次左到右,还有一次右到左,两者的顺序无所谓
先说说思路:
(从左往右遍历的时候)
遍历的时候用两个变量L和R记录左右括号出现的次数,一旦R>L,就说明当前遍历到的子串无效,为什么呢?因为多出来了一个左括号的话,只要右边还有右括号,就可以和左括号配对,还是有可能有效的,但是如果多出来一个右括号,那就没救了,没人和你配对啊,一直是多余的
然后当可能有人会问,只要左括号等于右括号,就一定有效吗?
对于一个完成了的序列来说,这个判断条件自然不成立,
比如
))((
但是我们是在一个一个的遍历啊,一开始就是右括号的话,R不就大于L了吗,那么将这个点作为开头的可能性都被我们抛弃了,所以在L == R的时候是可以保证括号的有效性的
缺陷:
虽然计数很方便,但是有一个致命的缺陷,那就是忽略了 L一直大于R的情况,比如
(((((((()
很明显这一串的最长有效括号为2,即最后面的()但是计数只能在L == R的时候保证括号的有效性,即只有在L = = R的时候才敢记录长度,却又只敢在R > L是舍弃当前位置,于是遍历上面的序列时,一直不舍弃,但又一直不敢记录长度,于是直到最后,R也没有等于L,
直到最后也没有记录长度,一直为0
但是这种缺陷也很容易解决,只要再来一次从右往左的遍历就行了!这就是上面所说的为什么要遍历两次的原因。
从右往左遍历的话就解决了L 一直大于 R的情况,两次遍历,互相弥补缺点
右往左的遍历其实和左往右差不多,改一下遍历顺序,改一下跳过条件就ok了
代码:
class Solution {
public:
int longestValidParentheses(string s) {
int L = 0, R = 0, maxLength = 0;
for(int i = 0;i<s.size();++i)//左往右
{
if(s[i]=='(') ++L;//记录左括号
else ++R;//记录右括号
//一旦两者相等,(就记录当前长度),不过依题意,我们要取最大长度
if(L == R) maxLength = max