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.
Solution in Java using DP 1:
<span style="font-size:18px;">public class Solution {
public int longestValidParentheses(String s) {
if(s==null||s.length()<2) return 0;
int[] opj = new int[s.length()];
//opj[i] denotes the maximum length of the valid substring from 0 to i, <span style="color:#ff0000;"><strong>containing s[i]!!!</strong></span>
//so we have:
opj[0] = 0;
int max = 0;
for(int i=1; i<s.length(); i++){
if(s.charAt(i)==')'){
int leftIndex = i - opj[i-1] -1;
//leftIndex is the index of the matching '(' if it exists.
if(leftIndex>=0&&s.charAt(leftIndex)=='('){
opj[i] = opj[i-1] + 2;
if(leftIndex>=2) opj[i]+=opj[leftIndex-1];
}
}
max = Math.max(opj[i], max);
}
return max;
}
}</span>
Note:注意opj[i]记录s[0...i]中最长的合法子字符串,但该字符串一定包含s[i]!就是说这个子串在s[0...i]中一定是靠右的!!而leftIndex则为该字串的左边界,所以opj[i]记录的最长子串为:s[leftIndex...i],并且s[leftIndex...i]必然形成了一个闭合的括号,即有"(...)"的形式。
Solution in Java using DP 2 (从右往左的DP):
public class Solution {
public int longestValidParentheses(String s) {
if(s==null||s.length()<2) return 0;
int len = s.length();
int[] opj = new int[len];
//opj[i] denotes the maximum length of the valid substring from i to len-1,
//containing s[i]!!! So we have:
opj[len-1] = 0;
int max = 0;
for(int i=len-2; i>=0; i--){
if(s.charAt(i)=='('){
int rightIndex = i+ opj[i+1] + 1;
//rightIndex is the index of the matching ')' if it exists.
if(rightIndex<len&&s.charAt(rightIndex)==')'){
opj[i] = opj[i+1] + 2;
if(rightIndex<len-2) opj[i]+=opj[rightIndex+1];
}
}
max = Math.max(opj[i], max);
}
return max;
}
}
Note: 从右往左算,则对opj[i],其记录的最长有效子串是在s[i...len-1]中靠左的子串,该子串必须包含s[i]。rightIndex为该子串的右边界。
Solution in Java using DP 3 (DP with a little modification):
public class Solution {
public int longestValidParentheses(String s) {
if(s==null||s.length()<2) return 0;
int len = s.length();
int[] opj = new int[len];
//opj[i] denotes the maximum length of the valid substring from i to len-1,
//containing s[i]!!! So we have:
opj[len-1] = 0;
int max = 0, valid=0;
//using valid to record if there is a matching ')' for a '('
//for each ')', valid++; for each '(', if valid>0 then this '(' is valid, and valid--;
for(int i=len-1; i>=0; i--){
if(s.charAt(i)=='('&&valid>0){
opj[i] = 2 + opj[i+1] + (i+opj[i+1]+1<len-2?opj[i+opj[i+1]+1+1]:0);
valid--;
}
else if(s.charAt(i)==')') valid++;
max = Math.max(opj[i], max);
}
return max;
}
}
Solution in Java using a stack and a boolean array:
public class Solution {
public int longestValidParentheses(String s) {
if(s==null||s.length()<2) return 0;
boolean[] valid = new boolean[s.length()];
Stack<Integer> indices = new Stack<Integer>();
for(int i=0; i<s.length(); i++){
if(s.charAt(i)=='(') indices.push(i);
if(s.charAt(i)==')'&&!indices.empty()){
valid[i] = true;
valid[indices.pop()]=true;
}
}
int max=0, len = 0;
for(int i=0; i<s.length();i++){
if(valid[i]) len++;
if(!valid[i]||i==s.length()-1) {
max = Math.max(max, len);
len=0;
}
}
return max;
}
}
Note:
很多人会说这道题用动规,可是用动规每次匹配后还要向前到上一个匹配跟这个匹配是否连接,时间复杂度为O(n^2),其实可以换个想法,用一个bool数组来标记已经匹配过的字符,找到最长的连续标记的长度就是所求的结果。只要遍历两遍数组,时间复杂度为O(n)。(last note is referenced from: http://www.cnblogs.com/easonliu/p/3637429.html)