http://leetcodenotes.wordpress.com/2013/10/19/leetcode-longest-valid-parentheses-%E8%BF%99%E7%A7%8D%E6%8B%AC%E5%8F%B7%E7%BB%84%E5%90%88%EF%BC%8C%E6%9C%80%E9%95%BF%E7%9A%84valid%E6%8B%AC%E5%8F%B7%E7%BB%84%E5%90%88%E6%9C%89%E5%A4%9A/
括号题也不是只用stack才能做,这题是算长度,所以stack那种一match就俩一起pop了的方式就不适合了。求极值,一维dp最好使。
- d[i]: 以i开头的最长valid parentheses有多长。
- d[i] =
- if (str[i] == ‘)’),以右括号开头必定invalid,d[i] = 0
- if (str[i] == ‘(‘),以左括号开头
- 我们想看对应的有木有右括号。因为d[i + 1]代表的sequence肯定是左括号开头右括号结尾,所以我们想catch((…))这种情况。j = i + 1 + d[i + 1],正好就是str[i]后面越过完整sequence的下一个,若是右括号,d[i] = 2 + d[i + 1]
- 除此之外,还有包起来后因为把后面的右括号用了而导致跟再往后也连起来了的情况,如((..))()()()。所以d[i]还要再加上j后面那一段的d[j + 1]
这个定义和最长公共字串那题的定义类似,都是“以某个固定位置开始/结束”。看两头的方式又像palindrome。从后往前的一维dp也不常见。挺好玩的,一下复习好多东西。
public int longestValidParentheses(String s) { if (s.length() == 0) return 0; int maxLen = 0; int[] d = new int[s.length()]; // d[i] means substring starts with i has max valid lenth of d[i] d[s.length() - 1] = 0; for (int i = s.length() - 2; i >= 0; i--) { if (s.charAt(i) == ')') d[i] = 0; else { int j = (i + 1) + d[i + 1]; if (j < s.length() && s.charAt(j) == ')') { d[i] = d[i + 1] + 2; //(()())的外包情况 if (j + 1 < s.length()) d[i] += d[j + 1];//()()的后面还有的情况 } } maxLen = Math.max(maxLen, d[i]); } return maxLen; }
—————————-用stack的做法———————————–
- stack里面装的一直是“还没配好对的那些可怜的括号的index”
- 是’(‘的时候push
- 是’)'的时候,说明可能配对了;看stack top是不是左括号,不是的话,push当前右括号
- 是的话,pop那个配对的左括号,然后update res:i和top的(最后一个配不成对的)index相减,就是i属于的这一段的当前最长。如果一pop就整个栈空了,说明前面全配好对了,那res就是最大=i+1
public int longestValidParentheses(String s) { int res = 0; Stack<Integer> stack = new Stack<Integer>(); char[] arr = s.toCharArray(); for (int i = 0; i < arr.length; i++) { if (arr[i] == ')' && !stack.isEmpty() && arr[stack.peek()] == '(') { stack.pop(); if (stack.isEmpty()) res = i + 1; else res = Math.max(res, i - stack.peek()); } else { stack.push(i); } } return res; }