The solution below has O(n) time complexity, and O(1) space complexity.
It is very intuitive.
We first traverse the string from left to right, looking for the longest valid substring of parens, using the 'count' method that is normally used to check the validity of parens. While doing this, we also record the maximum length of such a substring, if found.
Then, we do the same while going from right to left.
The algorithm would be as follows:
// Initialize variables
1. count = 0, len = 0, max_len_so_far = 0
// Check for longest valid string of parens while traversing from left to right
2. iterate over input string from left to right:
- len += 1
- if next character is '(',
count += 1
- if next character is ')',
count -= 1
- if (count == 0 and len > max_len_so_far),
max_len_so_far = len
- if (count < 0),
len = 0, count = 0
// Set count and len to zero again, but leave max_len_so_far untouched
3. count = 0, len = 0
// Now do a very similar thing while traversing from right to left
// (Though do observe the switched '(' and ')' in the code below)
4. iterate over input string from right to left:
- len += 1
- if next character is ')',
count += 1
- if next character is '(',
count -= 1
- if (count == 0 and len > max_len_so_far),
max_len_so_far = len
- if (count < 0),
len = 0, count = 0
// max_len_so_far is now our required answer
5. Finally,
return max_len_so_far
As an example, consider the string
"((())"
Suppose this string is zero-indexed.
We first go left to right.
So, at index 0, count would be 1, then 2 at index 1, 3 at index 2, 2 at index 3, and and 1 at index 4. In this step, max_len wouldn't even change, because count is never 0 again.
Then we go right to left.
At index 4, count is 1, then 2 at index 3, then 1 at index 2, then 0 at index 1.
At this point, len is 4 and max_len_so_far=0, so we set max_len = 4.
Then, at index 0, count is 1.
At this point, we stop and return 4, which is indeed the correct answer.
A proof of correctness is left as an inclusive exercise to the reader.
NOTE: This algorithm could also be very simply tweaked to return the longest valid substring of parentheses itself, rather than just its length.