32. Longest Valid Parentheses
题目:
Given a string containing just the characters '('
and ')'
, find the length of the longest valid (well-formed) parentheses substring.
For "(()"
, the longest valid parentheses substring is "()"
, which has length = 2.
Another example is ")()())"
, where the longest valid parentheses substring is "()()"
, which has length = 4.
链接: http://leetcode.com/problems/longest-valid-parentheses/
题解:
一开始想要尝试跟Valid Parentheses类似的解法,就是维护一个leftCount,一个rightCount,当leftCount < rightCount的时候清零,当leftCount = rightCount时,尝试更新max,结果出错。后来看到曹神的解法,才发现还应该从字符串尾部向前再来一遍。
下面是解法,two passes, Time Complexity - O(n), Space Complexity - O(1)。
public class Solution {
public int longestValidParentheses(String s) { //if left parentheses count > right parentheses count, case always valid
if(s == null || s.length() == 0)
return 0;
int start = -1, depth = 0, max = 0; for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == '(')
depth++;
else {
depth--;
if(depth < 0) {
start = i;
depth = 0;
} if(depth == 0)
max = Math.max(max, i - start);
}
} depth = 0;
start = s.length(); for(int i = s.length() - 1; i >= 0; i--) { //if right parentheses count > left parentheses count, case always valid
if(s.charAt(i) == ')')
depth++;
else {
depth--;
if(depth < 0) {
start = i;
depth = 0;
} if(depth == 0)
max = Math.max(max, start - i);
}
} return max;
}
}
还有一种解法是one pass, 方法是维护一个stack以及一个start index,遇到左括号入栈,遇到右括号出栈,当stack为空时说明左右括号平衡,计算i 与 start的距离, 否则左括号数目>右括号数目,计算i 与当前栈顶元素距离。 有小trick可以设置start = -1,这样代码里计算距离就可以不用 + 1了。还可以稍微简化一下,不过逻辑下面更清楚。
Time Complexity - O(n), Space Complexity - O(n)。
public class Solution {
public int longestValidParentheses(String s) {
if(s == null || s.length() == 0)
return 0;
Stack<Integer> stack = new Stack<>();
int start = 0, max = 0; for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == '(') //record index of each '('
stack.push(i);
else {
if(stack.isEmpty()) //try to find first '('
start = i + 1;
else {
stack.pop();
if(stack.isEmpty()) //left num = right num
max = Math.max(max, i - start + 1);
else //left > right, cal max with current top element in stack
max = Math.max(max, i - stack.peek());
}
}
} return max;
}
}
二刷:
可以用三种方法来做:
- 一种是曹神的方法,使用类似valid parentheses的方法。
- 维护一个depth,一个count。
- 从左向右遍历时并且当char == '('时,depth++,否则char = ')',depth--,这时候我们count++,因为找到了一对valid parenthese
- 当depth == 0的时候,左右括号平衡,可以尝试更新max, max = Math.max(max, count * 2)
- 接下来判断depth是否小于0,小于0的话depth = 0, count = 0,我们从头开始计算。
- 左右各自遍历一遍。从右向左遍历是为了计算类似于"()(()()"这种情况,这时depth always > 0,没办法得到max = 4的结论。
- 一种是一维DP,分好几种情况,画一个decision tree会比较清楚逻辑。
- 维护一个数组max[], 其中max[i]代表以s.charAt(i)结尾的longest valid parentheses的长度。我们考虑接下来集中情况。
- max[0] = 0,因为此时不能组成"()"。所以我们可以直接从 i = 1开始遍历
- 当前字符是'(', max[i] = 0,因为valid parentheses不能以'('结尾
- s.charAt(i - 1) = '(',正好可以组成一对括号。
- 当 i - 2 >= 0,max[i] = max[i - 2] + 2
- 当 i - 2 < 0, max[i] = 2
- 否则s.charAt(i - 1) = ')',此时我们也是继续进行判断
- 此时我们要求出i关于max[i - 1]对称的字符,就是 i - max[i - 1] - 1
- 假如i - max[i - 1] - 1 >= 0,并且 s.charAt(i - max[i - 1] - 1) == '('
- 此时表示从i - max[i - 1] - 1到i这一段都合理,所以这一部分等于max[i - 1] + 2, 我们要继续判断 i - max[i - 1] - 2
- 当i - max[i - 1] - 2 >= 0, 则 max[i] = max[i - 1] + 2 + max[i - max[i - 1] - 2]
- 否则max[i] = max[i - 1] + 2
- 此时表示从i - max[i - 1] - 1到i这一段都合理,所以这一部分等于max[i - 1] + 2, 我们要继续判断 i - max[i - 1] - 2
- 否则max[i] = 0,我们不改变什么
- 假如i - max[i - 1] - 1 >= 0,并且 s.charAt(i - max[i - 1] - 1) == '('
- 此时我们要求出i关于max[i - 1]对称的字符,就是 i - max[i - 1] - 1
- 在开头维护一个res = 0, 每次计算完max[i]之后尝试更新这个res,最后返回的也是这个res.
- 其实还可以继续简化,留给三刷了
否则,当前字符等于')',这时候继续判断几种情况
- 一种是利用一个stack来计算,这个留给三刷了,也是O(n)和O(n)
Java:
Time Complexity - O(n), Space Complexity - O(1)
public class Solution {
public int longestValidParentheses(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int count = 0, max = 0, depth = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
depth++;
} else {
depth--;
count++;
if (depth == 0) {
max = Math.max(max, count * 2);
}
if (depth < 0) {
depth = 0;
count = 0;
}
}
}
depth = 0;
count = 0;
for (int i = s.length() - 1; i >= 0; i--) {
char c = s.charAt(i);
if (c == ')') {
depth++;
} else {
depth--;
count++;
if (depth == 0) {
max = Math.max(max, count * 2);
}
if (depth < 0) {
depth = 0;
count = 0;
}
}
}
return max;
}
}
DP - Time Complexity - O(n), Space Complexity - O(n)
public class Solution {
public int longestValidParentheses(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int[] max = new int[s.length()]; // max[i] contains longest valid parentheses end at i
int res = 0;
for (int i = 1; i < max.length; i++) {
char c = s.charAt(i);
if (c == '(') {
max[i] = 0;
} else { // c = ')'
if (s.charAt(i - 1) == '(') {
max[i] = i - 2 >= 0 ? max[i - 2] + 2 : 2;
} else {
if (i - max[i - 1] - 1 >= 0 && s.charAt(i - max[i - 1] - 1) == '(') {
max[i] = max[i - 1] + 2 + (i - max[i - 1] - 2 >= 0 ? max[i - max[i - 1] - 2] : 0);
}
}
}
res = Math.max(max[i], res);
}
return res;
}
}
题外话:
1-20-2016
DP一直学得不好, divide and conquer也学得不好,需要多练习多思考。 像Matrix multiply, counting inversion,closest pair,merge sort之类的,一定要多多练习。还有Weighted quick union with path compression, run-length coding, Huffman Tree等等。
三刷:
还是使用曹神的方法,赞曹神思路清晰。
Java:
public class Solution {
public int longestValidParentheses(String s) {
if (s == null || s.length() == 0) return 0;
int max = 0, count = 0, start = 0, len = s.length();
for (int i = 0; i < len; i++) {
if (s.charAt(i) == '(') count++;
else count--;
if (count == 0) max = Math.max(max, i - start + 1);
if (count < 0) {
count = 0;
start = i + 1;
}
}
start = len - 1;
count = 0;
for (int i = len - 1; i >= 0; i--) {
if (s.charAt(i) == ')') count++;
else count--;
if (count == 0) max = Math.max(max, start - i + 1);
if (count < 0) {
count = 0;
start = i - 1;
}
}
return max;
}
}
Reference:
http://weibo.com/cpcs 曹神微博
http://www.cnblogs.com/springfor/p/3869495.html 小莹子
https://leetcode.com/discuss/9156/my-solution-using-one-stack-in-one-pass
https://leetcode.com/discuss/21549/simple-java-solution-o-n-time-one-stack
https://leetcode.com/discuss/8092/my-dp-o-n-solution-without-using-stack
https://leetcode.com/discuss/7609/my-o-n-solution-using-a-stack
32. Longest Valid Parentheses的更多相关文章
- [Leetcode][Python]32: Longest Valid Parentheses
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 32: Longest Valid Parentheseshttps://oj ...
- leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、
20. Valid Parentheses 错误解法: "[])"就会报错,没考虑到出现')'.']'.'}'时,stack为空的情况,这种情况也无法匹配 class Soluti ...
- 刷题32. Longest Valid Parentheses
一.题目说明 题目是32. Longest Valid Parentheses,求最大匹配的括号长度.题目的难度是Hard 二.我的做题方法 简单理解了一下,用栈就可以实现.实际上是我考虑简单了,经过 ...
- [LeetCode] 32. Longest Valid Parentheses 最长有效括号
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- leetcode 32. Longest Valid Parentheses
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- Java [leetcode 32]Longest Valid Parentheses
题目描述: Given a string containing just the characters '(' and ')', find the length of the longest vali ...
- leetcode problem 32 -- Longest Valid Parentheses
Longest Valid Parentheses Given a string containing just the characters '(' and ')', find the length ...
- 【Python】32. Longest Valid Parentheses
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- 【一天一道LeetCode】#32. Longest Valid Parentheses
一天一道LeetCode系列 (一)题目 Given a string containing just the characters '(' and ')', find the length of t ...
随机推荐
- dotNet中初始化器的使用
dotNet中初始化器的使用 2013年12月7日 13:27 有两类初始化器: 对象初始化器和集合初始化器 比如现在有一个User类: Public class User { public in ...
- mac os使用homebrew来管理后台服务
在linux下我们经常通过 service 或者 /etc/init.d/来管理我们的后台服务软件,并使用包管理器安装这些软件. 在mac下有homebrew这个好用的工具来安装软件,但是一直没有找到 ...
- OBIEE 11g:Error:nQSError 36010 Server version 318 cannot read the newer version of the repository
biee11g升级到最新版以后,发现了一些bug,需要回退到原来的版本,卸载掉升级包以后,启动BI服务,会报上述错误.这是因为资料库文件已经升级为了最新版本.这时候我们需要将资料库文件进行降版本操作. ...
- java实现mysql数据库的备份及还原
备份: public static void backup() { try { Runtime rt = Runtime.getRuntime(); // 调用 调用mysql的安装目录的命令 Pro ...
- ASP.NET MVC +EasyUI 权限设计(二)环境搭建
请注明转载地址:http://www.cnblogs.com/arhat 今天突然发现博客园出问题了,老魏使用了PC,手机,平板都访问博客园了,都是不能正常的访问,原因是不能加载CSS,也就是不能访问 ...
- 【BZOJ 1090】[SCOI2003]字符串折叠
Description 折 叠的定义如下: 1. 一个字符串可以看成它自身的折叠.记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) SSSS…S(X个S). ...
- linux 命令小结
chkconfig --list 查询所有服务运行情况 修改文件夹权限: 在Linux中,权限的所有者分为用户权限,组权限和其他权限,分别是用字母u, g, o 代表权限分为:读 r , 写 w , ...
- 学习KnockOut第一篇之Hello World
学习KnockOut第一篇之Hello World 笔者刚开始学习KnockOut.写的内容就相当于一个学习笔记.且在此处向官网致敬,比较喜欢他们家的Live Example版块,里面有jsFiddl ...
- NPOI读取Excel数据应用
NPOI 是 POI 项目的 .NET 版本.使用 NPOI 你就可以在没有安装 Office 或者相应环境的机器上对 WORD/EXCEL 文档进行读写.NPOI是构建在POI 3.x版本之上的,它 ...
- Django 学习笔记之一 环境搭建
以后的文章都是在windows系统进行的 首先下载安装Django包 方式1:使用 pip或easy_insatll来进行安装 同时按住win+R键,弹出命令行运行框输入,pip install Dj ...