(Version 1.3)

这题在LeetCode上的标签比较有欺骗性,虽然标签写着有DP,但是实际上根本不需要使用动态规划,相反的,使用动态规划反而会在LeetCode OJ上面超时。这题正确的做法应该和Largest Rectangle in Histogram那几个使用stack来记录并寻找左边界的题比较类似,因为在仔细分析问题并上手尝试解决时,会发现问题的关键在于怎么判定一个valid parentheses子串的起始位置,或者说当遇到一个')'时,怎么知道要加到哪里去。

第一次做的时候因为标签是DP,所以写了一个无脑版本的DP,时间复杂度是O(N^2)的,结果不出意料得到了Time Limit Exceeded,代码如下,

 public class Solution {
public int longestValidParentheses(String s) {
if (s.length() < 2) {
return 0;
}
int result = 0;
boolean[][] isValid = new boolean[s.length()][s.length()];
int len = s.length();
for (int i = 0; i < isValid.length - 1; i++) {
if (s.charAt(i) == '(' && s.charAt(i + 1) == ')') {
isValid[i][i + 1] = true;
result = 2;
}
}
for (int l = 4; l <= len; l += 2) {
int bound = len - l;
for (int i = 0; i <= bound; i++) {
int j = i + l - 1;
isValid[i][j] = (isValid[i + 1][j - 1] && s.charAt(i) == '(' && s.charAt(j) == ')')
|| (isValid[i][j - 2] && s.charAt(j - 1) == '(' && s.charAt(j) == ')')
|| (isValid[i + 2][j] && s.charAt(i) == '(' && s.charAt(i + 1) == ')');
if (isValid[i][j] && l > result) {
result = l;
}
}
}
return result;
}
}

于是忽然意识到这题既然是求substring而不是subsequence,没准可以不用DP来做,因为substring的话感觉好像并不会有很多overlapping的subproblem,而是可以不断地明确砍掉已经处理过的substring进而缩小问题范围,于是想到了依然采用类似Valid Parentheses的计数的方法,用O(N)的时间复杂度和O(1)的空间复杂度就可以解决,代码如下:

 public class Solution {
public int longestValidParentheses(String s) {
if (s.length() < 2) {
return 0;
}
int result = 0;
int count = 0;
int diff = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
count++;
diff++;
} else {
diff--;
if (diff < 0) {
diff = 0;
count = 0;
} else if (diff == 0 && result < (count << 1)) {
result = count << 1;
}
}
}
count = 0;
diff = 0;
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == ')') {
count++;
diff++;
} else {
diff--;
if (diff < 0) {
diff = 0;
count = 0;
} else if (diff == 0 && result < (count << 1)) {
result = count << 1;
}
}
}
return result;
}
}

其中用右移一位运算代替了乘2,纯属个人爱好,可能不是一个好的代码习惯。这个代买的思路是先从左向右走一次,每当发现所有在考虑的左右括号完全匹配(即diff == 0时)尝试更新result。第一次走下来如果左括号一直多于右括号的话就无法得到答案,所以再从右到左走一次,这样两次当中可以确保至少有一次能够使得diff == 0,以取得正确答案。

这一版本的答案是由于之前一直在思考DP的做法而产生的,如果向Valid Parentheses的解法靠拢尝试使用stack的话应该会有使用额外空间但是只需要扫一次的解法。

下面是重写的code ganker的解法(http://blog.csdn.net/linhuanmars/article/details/20439613),思路主要是:类似Valid Parentheses,用一个stack按顺序记录'('的index,再用一个变量记录当前可能的substring的开头。每当遇到一个')'时,若stack非空,则pop出一个元素,若pop之后非空,说明当前只能匹配到上一个尚未被匹配的'(',即stack.peek();若stack为空,说明可以一直匹配到start。当发现')'多于'('时,即在遇到')'时stack为空,则需要移动start到至少最后一个')'的下一位,因为易得当')'多于'('时,不可能再继续append到之前的任何substring得到依然valid的,所以可以砍掉前面的东西,缩小需要考虑的范围。代码如下:

 public class Solution {
public int longestValidParentheses(String s) {
Stack<Integer> stack = new Stack<>();
int result = 0;
int start = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
if (!stack.isEmpty()) {
stack.pop();
result = stack.isEmpty() ? Math.max(result, i - start + 1) : Math.max(result, i - stack.peek());
} else {
start = i + 1;
}
}
} return result;
}
}

这个解法的关键insight在于理解用stack存index的真正目的是记录可能的substring左边界,用于在找到一个')'判断左边界应该在哪,值得集中练习掌握,LeetCode上面相关的题目还有上面提到的Largest Rectangle in Histogram,Trapping Rain Water等。

[LeetCode] Longest Valid Parentheses -- 挂动态规划羊头卖stack的狗肉的更多相关文章

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

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

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

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

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

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

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

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

  5. [LeetCode] Longest Valid Parentheses

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

  6. LeetCode: Longest Valid Parentheses 解题报告

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

  7. leetcode: Longest Valid Parentheses分析和实现

    题目大意:给出一个只包含字符'('和')'的字符串S,求最长有效括号序列的长度. 很有趣的题目,有助于我们对这种人类自身制定的规则的深入理解,可能我们大多数人都从没有真正理解过怎样一个括号序列是有效的 ...

  8. leetcode Longest Valid Parentheses python

    class Solution(object): def longestValidParentheses(self, s): """ :type s: str :rtype ...

  9. LeetCode之“动态规划”:Valid Parentheses && Longest Valid Parentheses

    1. Valid Parentheses 题目链接 题目要求: Given a string containing just the characters '(', ')', '{', '}', '[ ...

随机推荐

  1. 更新tensorflow支持GPU时出错

    sudo pip install --upgrade tensorflow-gpu Operation not permitted: '/tmp/pip-Sx_vMg-uninstall/System ...

  2. 使用glReadPixels 读取颜色缓存,深度缓存和模板缓存数据

    glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *p ...

  3. Python基础语法02-运算符

    Python 运算符 算术运算符 比较(关系)运算符 赋值运算符 逻辑运算符 位运算符 成员运算符 身份运算符 运算符优先级 Python运算符优先级 以下表格列出了从最高到最低优先级的所有运算符: ...

  4. Opencv 改进的外接矩形合并拼接方法

    上一篇中的方法存在的问题是矩形框不够精确,而且效果不能达到要求 这里使用凸包检测的方法,并将原来膨胀系数由20缩小到5,达到了更好的效果 效果图: 效果图: 代码: #include <open ...

  5. Maven plugin提示错误“Plugin execution not covered by lifecycle configuration”

    myeclipse在其POM文件的一处提示出错如下: Plugin execution not covered by lifecycle configuration: org.apache.maven ...

  6. Win7/Win2008下IIS配置Asp网站启用父路径的设置方法(已解决)

    Win7/Win2008下IIS配置Asp网站启用父路径的设置方法(已解决) 在Win7/Win2008下IIS配置Asp网站启用父路径的设置方法与win2003下不同,看看下图就知道了.

  7. 怎样隐藏Windows7 系统保留分区

    安装Windows7操作系统时须要预留出100MB左右的系统保留盘分区.在Windows7激活是必须给它分配盘符,否则无法将其成功激活,但是激活后该盘符永久地显示了出来,怎样将其隐藏掉呢? 1.隐藏前 ...

  8. java监听器演示样例

    监听器的原理是观察者模式.就像明星(事件源)聚拢了一群粉丝(观察者).当明星有啥举动的时候会通过粉丝们报道出去. 订阅信息.计算器button都是该原理的应用. 以下写了一个监听器的小样例: pack ...

  9. vue-导入静态文件

    vue导入静态文件不用像网上说的那么麻烦,其实跟普通Django项目导入类似,vue项目中有一个static文件,将你的静态文件放入到里面,然后引入就好 导入的时候和普通Django程序类似:↓ &l ...

  10. Kubernetes基本概念之Label

    系列目录 在为对象定义好Label后,其他对象就可以通过Label来对对象进行引用.Label的最常见的用法便是通过spec.selector来引用对象. apiVersion: v1 kind: R ...