Longest Valid Parentheses — LeetCode

Problem statement

Alkesh Ghorpade
Nerd For Tech

--

Given a string containing just the characters ‘(‘ and ‘)’, return the length of the longest valid (well-formed) parentheses substring.

Problem statement taken from: https://leetcode.com/problems/longest-valid-parentheses

Example 1:

Input: s = '(()'
Output: 2
Explanation: The longest valid parentheses substring is '()'.

Example 2:

Input: s = ')()())'
Output: 4
Explanation: The longest valid parentheses substring is '()()'.

Example 3:

Input: s = ''
Output: 0

Constraints:

- 0 <= s.length <= 3 * 10^4
- s[i] is '(', or ')'

Solutions for Longest Valid Parentheses

Approach 1: Brute Force

The brute force approach is to generate all the substrings and check whether every string is valid parentheses. If the substring is valid and the length exceeds the maximum length seen so far, then update the maximum length. We return this maximum length as the longest valid parentheses.

The problem with this approach is the time complexity which is O(n³). Three nested for loops will be used. The first two will generate all the substrings, and the third inner loop will verify whether the substring is valid parentheses.

Approach 2: Using Stack

An efficient way to solve the longest valid parentheses is using a Stack. The solution is similar to our approach in valid parentheses problem. Instead of pushing the open brackets ( to the stack, we push the indexes of the opening brackets.

The algorithm for this approach is as follows:

- initialize stack<int> st
// push -1 to the stack to provide the base
// for the next valid set of parentheses
st.push(-1)

- set result = 0

- loop for i = 0; i < str.size(); i++
// if opening bracket, push the index i

- if str[i] == '('
- st.push(i)

- else
// if str[i] == ')'

// pop the last encountered opening bracket's index
- if !st.empty()
- st.pop()
- end if

// if the length formed with the base of the current valid substring
// is more than max so far
- if !st.empty
- set result = max(result, i - st.top())
- else
- st.push(i)
- end if
- end if
- end for

- return result

A C++ snippet of this algorithm is as below:

int longestValidParentheses(string s) {
stack<int> stk;
stk.push(-1);

int result = 0;

for (int i = 0; i < str.size(); i++) {
if (str[i] == '(') {
stk.push(i);
} else {
if (!stk.empty()) {
stk.pop();
}

if (!stk.empty()) {
result = max(result, i - stk.top());
} else {
stk.push(i);
}
}
}

return result;
}

The time complexity of this approach is O(n) because we are iterating over the string once. The space complexity is also O(n), as we used an additional data structure, Stack.

Approach 3: Using left and right counters

Using two counters, we can solve this problem in O(1) time.

  • The idea is to scan the string from left to right.
  • We keep track of the number of open and closed braces using left and right counters. We increment the left and right counter by 1 when identifying an opening ( and closing ) braces.
  • When the left and right counters are equal, the length of the current substring is calculated. If it exceeds the previous longest valid parentheses, we update the result with the current substring length.
  • At any point while scanning, if the right counter value exceeds the left counter, the substring is not a valid parentheses string. We set the left and right counters to 0.
  • We then scan the string from right to left and repeat similar steps above.

Let’s check the algorithm for this approach.

Algorithm

- set left, right, maxLength = 0
n = s.length

- loop for i = 0; i < n; i++
- if s[i] == '('
- increment left: left++
- else
- increment right: right++
- end if

- if left == right
- update maxLength: maxLength = max(maxLength, 2 * right)
- else if right > left
- set left, right = 0, 0
- end if
- end for

- set left, right = 0, 0

- loop for i = 0; i < n; i++
- if s[i] == '('
- increment left: left++
- else
- increment right: right++
- end if

- if left == right
- update maxLength: maxLength = max(maxLength, 2 * right)
- else if left > right
- set left, right = 0, 0
- end if
- end for

- return maxLength

The time complexity of the above approach is O(n), and the space complexity is O(1).

Check out our solutions in C++, Golang, and Javascript.

C++ solution

class Solution {
public:
// Main function to return the length of
// the longest valid parentheses
int longestValidParentheses(string s) {
int left = 0, right = 0, maxLength = 0;
int n = s.length();

// iterate the string from left to right
for(int i = 0; i < n; i++) {
if(s[i] == '(') {
left++;
} else {
right++;
}

// if left is equal to right, we found a
// valid parentheses substring
if(left == right) {
maxLength = max(maxLength, 2 * right);
} else if (right > left) {
// reset the left and right counter when we have
// invalid parentheses substring
left = 0;
right = 0;
}
}

left = 0;
right = 0;

// iterate the string from right to left
for(int i = n - 1; i >= 0; i--) {
if(s[i] == '(') {
left++;
} else {
right++;
}

// if left is equal to right, we found a
// valid parentheses substring
if(left == right) {
maxLength = max(maxLength, 2 * right);
} else if (left > right) {
// reset the left and right counter when we have
// invalid parentheses substring
left = 0;
right = 0;
}
}

return maxLength;
}
};

Golang solution

// Main function to return the length of
// the longest valid parentheses
func longestValidParentheses(s string) int {
left, right, maxLength := 0, 0, 0
n := len(s)

// iterate the string from left to right
for i := 0; i < n; i++ {
if s[i] == '(' {
left++
} else {
right++
}

// if left is equal to right, we found a
// valid parentheses substring
if left == right {
maxLength = max(maxLength, 2 * right)
} else if (right > left) {
// reset the left and right counter when we have
// invalid parentheses substring
left = 0
right = 0
}
}

left = 0
right = 0

// iterate the string from right to left
for i := n - 1; i >= 0; i-- {
if s[i] == '(' {
left++
} else {
right++
}

// if left is equal to right, we found a
// valid parentheses substring
if left == right {
maxLength = max(maxLength, 2 * right)
} else if (left > right) {
// reset the left and right counter when we have
// invalid parentheses substring
left = 0
right = 0
}
}

return maxLength
}

func max(a, b int) int {
if a > b {
return a
}

return b
}

JavaScript solution

// Main function to return the length of
// the longest valid parentheses
var longestValidParentheses = function(s) {
let left = 0, right = 0, maxLength = 0;
let n = s.length;

// iterate the string from left to right
for(let i = 0; i < n; i++) {
if(s[i] == '(') {
left++;
} else {
right++;
}

// if left is equal to right, we found a
// valid parentheses substring
if(left == right) {
maxLength = Math.max(maxLength, 2 * right);
} else if (right > left) {
// reset the left and right counter when we have
// invalid parentheses substring
left = 0;
right = 0;
}
}

left = 0;
right = 0;

// iterate the string from right to left
for(let i = n - 1; i >= 0; i--) {
if(s[i] == '(') {
left++;
} else {
right++;
}

// if left is equal to right, we found a
// valid parentheses substring
if(left == right) {
maxLength = Math.max(maxLength, 2 * right);
} else if (left > right) {
// reset the left and right counter when we have
// invalid parentheses substring
left = 0;
right = 0;
}
}

return maxLength;
};

Dry Run

Let’s dry-run our algorithm to see how the solution works.

Input: s = ')()())'

Step 1: set left = 0, right = 0, maxLength = 0
n = s.size()
= 6

Step 2: loop for i = 0; i < n
0 < 6
true

if s[i] == '('
s[0] == '('
')' == '('
false
else
right++
right = 1

if left == right
0 == 1
false
else if right > left
1 > 0
true

left = 0
right = 0

i++
i = 1

Step 3: loop for i < n
1 < 6
true

if s[i] == '('
s[1] == '('
'(' == '('
true
left++
left = 1

if left == right
1 == 0
false
else if right > left
0 > 1
false

i++
i = 2

Step 4: loop for i < n
2 < 6
true

if s[i] == '('
s[2] == '('
')' == '('
false
else
right++
right = 1

if left == right
1 == 1
true

maxLength = max(maxLength, 2 * right)
= max(0, 2 * 1)
= max(0, 2)
= 2

i++
i = 3

Step 5: loop for i < n
3 < 6
true

if s[i] == '('
s[3] == '('
'(' == '('
true
left++
left = 2

if left == right
2 == 1
false
else if right > left
1 > 2
false

i++
i = 4

Step 6: loop for i < n
4 < 6
true

if s[i] == '('
s[4] == '('
')' == '('
false
else
right++
right = 2

if left == right
2 == 2
true

maxLength = max(maxLength, 2 * right)
= max(2, 2 * 2)
= max(2, 4)
= 4

i++
i = 5

Step 7: loop for i < n
5 < 6
true

if s[i] == '('
s[5] == '('
')' == '('
false
else
right++
right = 3

if left == right
2 == 3
false
else
left = 0
right = 0

i++
i = 6

Step 8: loop for i < n
6 < 6
false

Step 9: left = 0
right = 0

Step 10: loop for i = n - 1; i >= 0
i = 6 - 1 = 5
i >= 0
5 >= 0
true

if s[i] == '('
s[5] == '('
')' == '('
false
else
right++
right = 1

if left == right
0 == 1
false
else if left > right
0 > 1
false

i--
i = 4

Step 11: loop for i >= 0
4 >= 0
true

if s[i] == '('
s[4] == '('
')' == '('
false
else
right++
right = 2

if left == right
0 == 2
false
else if left > right
0 > 2
false

i--
i = 3

Step 12: loop for i >= 0
3 >= 0
true

if s[i] == '('
s[3] == '('
'(' == '('
true
left++
left = 1

if left == right
1 == 2
false
else if left > right
1 > 2
false

i--
i = 2

Step 13: loop for i >= 0
2 >= 0
true

if s[i] == '('
s[2] == '('
')' == '('
false
else
right++
right = 3

if left == right
1 == 3
false
else if left > right
1 > 3
false

i--
i = 1

Step 14: loop for i >= 0
1 >= 0
true

if s[i] == '('
s[1] == '('
'(' == '('
true
left++
left = 2

if left == right
2 == 3
false
else if left > right
2 > 3
false

i--
i = 0

Step 15: loop for i >= 0
0 >= 0
true

if s[i] == '('
s[1] == '('
')' == '('
false
else
right++
right = 4

if left == right
2 == 4
false
else if left > right
2 > 4
false

i--
i = -1

Step 16: loop for i >= 0
-1 >= 0
false

Step 17: return maxLength

We return the answer as 4.

Originally posted at https://alkeshghorpade.me.

--

--