Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"

Example 2:

Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"

这道求最长有效括号比之前那道 Valid Parentheses 难度要大一些,这里还是借助栈来求解,需要定义个 start 变量来记录合法括号串的起始位置,遍历字符串,如果遇到左括号,则将当前下标压入栈,如果遇到右括号,如果当前栈为空,则将下一个坐标位置记录到 start,如果栈不为空,则将栈顶元素取出,此时若栈为空,则更新结果和 i - start + 1 中的较大值,否则更新结果和 i - st.top() 中的较大值,参见代码如下:

解法一:

class Solution {
public:
int longestValidParentheses(string s) {
int res = , start = , n = s.size();
stack<int> st;
for (int i = ; i < n; ++i) {
if (s[i] == '(') st.push(i);
else if (s[i] == ')') {
if (st.empty()) start = i + ;
else {
st.pop();
res = st.empty() ? max(res, i - start + ) : max(res, i - st.top());
}
}
}
return res;
}
};

还有一种利用动态规划 Dynamic Programming 的解法,可参见网友喜刷刷的博客。这里使用一个一维 dp 数组,其中 dp[i] 表示以 s[i-1] 结尾的最长有效括号长度(注意这里没有对应 s[i],是为了避免取 dp[i-1] 时越界从而让 dp 数组的长度加了1),s[i-1] 此时必须是有效括号的一部分,那么只要 dp[i] 为正数的话,说明 s[i-1] 一定是右括号,因为有效括号必须是闭合的。当括号有重合时,比如 "(())",会出现多个右括号相连,此时更新最外边的右括号的 dp[i] 时是需要前一个右括号的值 dp[i-1],因为假如 dp[i-1] 为正数,说明此位置往前 dp[i-1] 个字符组成的子串都是合法的子串,需要再看前面一个位置,假如是左括号,说明在 dp[i-1] 的基础上又增加了一个合法的括号,所以长度加上2。但此时还可能出现的情况是,前面的左括号前面还有合法括号,比如 "()(())",此时更新最后面的右括号的时候,知道第二个右括号的 dp 值是2,那么最后一个右括号的 dp 值不仅是第二个括号的 dp 值再加2,还可以连到第一个右括号的 dp 值,整个最长的有效括号长度是6。所以在更新当前右括号的 dp 值时,首先要计算出第一个右括号的位置,通过 i-3-dp[i-1] 来获得,由于这里定义的 dp[i] 对应的是字符 s[i-1],所以需要再加1,变成 j = i-2-dp[i-1],这样若当前字符 s[i-1] 是左括号,或者j小于0(说明没有对应的左括号),或者 s[j] 是右括号,此时将 dp[i] 重置为0,否则就用 dp[i-1] + 2 + dp[j] 来更新 dp[i]。这里由于进行了 padding,可能对应关系会比较晕,大家可以自行带个例子一步一步执行,应该是不难理解的,参见代码如下:

解法二:

class Solution {
public:
int longestValidParentheses(string s) {
int res = , n = s.size();
vector<int> dp(n + );
for (int i = ; i <= n; ++i) {
int j = i - - dp[i - ];
if (s[i - ] == '(' || j < || s[j] == ')') {
dp[i] = ;
} else {
dp[i] = dp[i - ] + + dp[j];
res = max(res, dp[i]);
}
}
return res;
}
};

此题还有一种不用额外空间的解法,使用了两个变量 left 和 right,分别用来记录到当前位置时左括号和右括号的出现次数,当遇到左括号时,left 自增1,右括号时 right 自增1。对于最长有效的括号的子串,一定是左括号等于右括号的情况,此时就可以更新结果 res 了,一旦右括号数量超过左括号数量了,说明当前位置不能组成合法括号子串,left 和 right 重置为0。但是对于这种情况 "(()" 时,在遍历结束时左右子括号数都不相等,此时没法更新结果 res,但其实正确答案是2,怎么处理这种情况呢?答案是再反向遍历一遍,采取类似的机制,稍有不同的是此时若 left 大于 right 了,则重置0,这样就可以 cover 所有的情况了,参见代码如下:

解法三:

class Solution {
public:
int longestValidParentheses(string s) {
int res = , left = , right = , n = s.size();
for (int i = ; i < n; ++i) {
(s[i] == '(') ? ++left : ++right;
if (left == right) res = max(res, * right);
else if (right > left) left = right = ;
}
left = right = ;
for (int i = n - ; i >= ; --i) {
(s[i] == '(') ? ++left : ++right;
if (left == right) res = max(res, * left);
else if (left > right) left = right = ;
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/32

类似题目:

Remove Invalid Parentheses

Different Ways to Add Parentheses

Generate Parentheses

Valid Parentheses

参考资料:

https://leetcode.com/problems/longest-valid-parentheses/

https://bangbingsyb.blogspot.com/2014/11/leetcode-longest-valid-parentheses.html

https://leetcode.com/problems/longest-valid-parentheses/discuss/14126/My-O(n)-solution-using-a-stack

https://leetcode.com/problems/longest-valid-parentheses/discuss/14133/My-DP-O(n)-solution-without-using-stack

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Longest Valid Parentheses 最长有效括号的更多相关文章

  1. [Leetcode] longest valid parentheses 最长的有效括号

    Given a string containing just the characters'('and')', find the length of the longest valid (well-f ...

  2. [LeetCode] 32. Longest Valid Parentheses 最长有效括号

    Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...

  3. [leetcode]32. Longest Valid Parentheses最长合法括号子串

    Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...

  4. 032 Longest Valid Parentheses 最长有效括号

    给一个只包含 '(' 和 ')' 的字符串,找出最长的有效(正确关闭)括号子串的长度.对于 "(()",最长有效括号子串为 "()" ,它的长度是 2.另一个例 ...

  5. 32. Longest Valid Parentheses最长有效括号

    参考: 1. https://leetcode.com/problems/longest-valid-parentheses/solution/ 2. https://blog.csdn.net/ac ...

  6. [LeetCode] Longest Valid Parentheses 解题思路

    Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...

  7. [LeetCode] Longest Valid Parentheses

    第一种方法,用栈实现,最容易想到,也比较容易实现,每次碰到‘)’时update max_len,由于要保存之前的‘(’的index,所以space complexity 是O(n) // 使用栈,时间 ...

  8. [LeetCode] Longest Valid Parentheses 动态规划

    Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...

  9. LeetCode: Longest Valid Parentheses 解题报告

    Longest Valid Parentheses Given a string containing just the characters '(' and ')', find the length ...

随机推荐

  1. 设计模式(十三)代理模式(Proxy Pattern)

    一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...

  2. Sublime Text 2 快捷操作

    Sublime Text 2 包含了大量快捷操作,而且还很方便修改和追加自己喜欢的快捷键. 查看快捷键的方式也很简单: 点击菜单栏:Preferences->Key Bindings –Defa ...

  3. 同步辅助类CountDownLatch用法

    CountDownLatch是一个同步辅助类,犹如倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则使当前线程处于等待状态,调用countDow ...

  4. [连载]《C#通讯(串口和网络)框架的设计与实现》- 13.中英文版本切换设计

    目       录 第十三章     中英文版本切换设计... 2 13.1        不用自带的资源文件的理由... 2 13.2        配置文件... 2 13.3        语言 ...

  5. Java中日期的转化

    4.如何取得年月日.小时分秒? 创建java.util.Calendar实例(Calendar.getInstance()),调用其get()方法传入不同的参数即可获得参数所对应的值,如:calend ...

  6. Java三大框架之——Hibernate关联映射与级联操作

    什么是Hibernate中的关联映射? 简单来说Hibernate是ORM映射的持久层框架,全称是(Object Relational Mapping),即对象关系映射. 它将数据库中的表映射成对应的 ...

  7. linux(七)__shell脚本编程

    一.什么是shell脚本 shell除了是命令解释器之外还是一种编程语言,用shell编写的程序类似于DOS下的批处理程序. 它是用户与操作系统之间的一个接口. shell脚本语言非常擅长处理文本类型 ...

  8. 交易系统使用storm,在消息高可靠情况下,如何避免消息重复

    概要:在使用storm分布式计算框架进行数据处理时,如何保证进入storm的消息的一定会被处理,且不会被重复处理.这个时候仅仅开启storm的ack机制并不能解决上述问题.那么该如何设计出一个好的方案 ...

  9. [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)

    原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...

  10. CSS代码规范

    空格 选择器 与 { 之间必须包含空格. 列表型属性值 书写在单行时,, 后必须跟一个空格. 属性名 与之后的 : 之间不允许包含空格, : 与 属性值 之间必须包含空格. margin: 0; .+ ...