Given a string s consisting of opening and closing parenthesis '(' and ')', find the length of the longest valid parenthesis substring.
A valid parenthesis substring is one where every opening bracket '(' has a corresponding closing bracket ')' in the correct order.
Examples:
Input: s = "())"
Output: 2
Explanation: The longest valid parentheses substring is "()".
Input: s = "(()())"
Output: 6
Explanation: The entire string "(()())" is a valid parentheses substring of length 6.
[Expected Approach - 1] Using Stack - O(n) Time and O(n) Space
We use a stack to track indices of unmatched '('. By also recording the index of the last unmatched ')', we can calculate the length of each valid substring and keep track of the maximum length found.
Steps below to solve the problem:
- For every opening parenthesis, we push its index onto the stack.
- For every closing parenthesis, we pop the stack.
- If the stack becomes empty after popping, it means we've encountered an unmatched closing parenthesis, so we push the current index to serve as a base for the next potential valid substring.
- If the stack is not empty, we calculate the length of the valid substring by subtracting the index at the top of the stack from the current index.
- A variable maxLength keeps track of the maximum length of valid parentheses encountered during the traversal.
[Expected Approach - 2] Using Dynamic Programming- O(n) Time and O(n) Space
The idea is to solve this problem using dynamic programming (DP) where dp[i] represents the length of the longest valid parentheses substring ending at index i. If a valid substring ends at i, we calculate and store the length of that substring in dp[i].
Steps below to solve the problem:
- If we encounter an opening parenthesis, we can't form a valid substring yet, so we move to the next character.
- If we encounter a closing parenthesis, we check the previous character to determine if it forms a valid substring.
=> If the previous character is '(', we have a valid pair, so dp[i] = dp[i-2] + 2 (if i-2 is valid).
=> If the previous character is ')', check if the substring before it forms a valid substring. We use dp[i-1] to determine where the valid substring might start. - Also, store the maximum length of valid parentheses during the traversal.
[Expected Approach - 3] Using Two Traversals - O(n) Time and O(1) Space
The idea is to solve the problem using two traversals of the string, one from left to right and one from right to left, while keeping track of the number of open and close parentheses using two counters: open and close.
Steps below to solve the problem:
- Use two counters: open and close.
- Traverse once left to right and once right to left.
- For each character:
=> Increment open if '(', else increment close.
=> If open == close, update max length = 2 * close.
=> If imbalance occurs (close > open in left-to-right, or open > close in right-to-left),
reset both counters. - Two passes ensure both extra ')' and extra '(' cases are handled.