import java.util.Stack;
/**
* 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.
*
* Follow up:
*
* What if there are curly bracs and brakets as well? {} []?
*
* Tags: DP, String
*/
class LongestValidParen {
public static void main(String[] args) {
System.out.println(longestValidParentheses("(()")); // 2
System.out.println(longestValidParentheses("()(()")); // 2
System.out.println(longestValidParentheses("()(()(")); // 2
System.out.println(longestValidParentheses("()(()((")); // 2
System.out.println(longestValidParentheses("()(()(((")); // 2
System.out.println(longestValidParentheses("(((((()")); // 2
System.out.println(longestValidParentheses(")()())")); // 4
System.out.println(longestValidParentheses("((((((")); // 0
System.out.println(longestValidParentheses("))))))")); // 0
System.out.println(longestValidParentheses(")()(())")); // 6
System.out.println(longestValidParentheses("(())()")); // 6
System.out.println(longestValidParentheses(")()()")); // 4
}
/**
* Optimized DP
* Build a stack for indices of open parentheses
* Traverse the string, if current is open paren, push to stack
* Otherwise, its close paren.
* If stack is empty, no open paren left, reset len to 0.
* If not, pop the index from stack, matchedLen = current index - index of
* pop open paren + 1
* If stack is empty, means this matchedLen can be added to the whole len
* If not,
*/
public static int longestValidParentheses(String s) {
if (s == null) return 0;
Stack<Integer> stack = new Stack<Integer>();
int maxLen = 0;
int len = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') stack.push(i);
else if (s.isEmpty()) len = 0;
else {
int matchedPos = stack.pop();
int matchedLen = i - matchedPos + 1;
if (s.isEmpty()) { // ()()
len += matchedLen;
matchedLen = len;
} else matchedLen = i - stack.peek(); // ()(()()
maxLen = Math.max(maxLen, matchedLen);
}
}
return maxLen;
}
/**
* DP
*/
public int longestValidParenthesesB(String s) {
if (s == null || s.length() == 0) return 0;
Stack<Integer> stack = new Stack<>(); // Save indices of '('
int[] dp = new int[s.length()]; // Store the length of the current longest valid sequence.
int max = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') stack.push(i);
else if (stack.isEmpty()) continue;
else if (stack.peek() > 0)
dp[i] = 2 + dp[stack.pop() - 1] + dp[i - 1]; // connect two valid sequences, or increase the length of current valid sequence.
else {
dp[i] = 2 + dp[i - 1]; // leftmost char is a '('
stack.pop();
}
max = Math.max(dp[i], max);
}
return max;
}
/**
* Two pass
* Use a stack to store index of unmatched parentheses
* Go through the stack and find maximum of difference between indices
* Include len - first and last - 0
*/
public int longestValidParenthesesC (String s) {
Stack<Integer> st = new Stack<Integer>(); // store the index of unmatched parens
int len = s.length();
int longest = 0;
for (int i = 0; i < len; i++) {
if (s.charAt(i) == '(') st.push(i);
else if (s.charAt(i) == ')' && !st.isEmpty() && s.charAt(st.peek()) == '(') st.pop(); // pop if there is a pair
else st.push(i); // right paren, empty or top is also right
}
if (st.isEmpty()) return len; // all valid
/*calculate longest length between each unpaired*/
int a = len, b = 0;
while (!st.isEmpty()) {
b = st.pop();
longest = Math.max(longest, a - b - 1); // update longest
a = b;
}
longest = Math.max(longest, a); // compare with last - 0
return longest;
}
}