Longest Valid Parentheses
You are given a string containing only the characters ( and ). Find the length of the longest run of characters, sitting side by side, that is properly balanced. Properly balanced means every opening bracket has a matching closing bracket after it, and the brackets never close before they open. Only a closing bracket can finish a valid run, so keep, for every position, the length of the valid run ending exactly there . A closing bracket either sits right after an opening one, or it closes a bracket that sits just before a run already counted — in which case the run before that one gets glued on as well.
Constraints
- 0 ≤ s.length ≤ 30000
- s contains only the characters ( and )
- The answer is a length, not the substring itself
Example
s = ")()())"4Explanation The longest balanced run is "()()" , which sits at positions 1 to 4.
In plain terms
- Balanced
- Every ( has a matching ) after it and nothing closes out of order. "(())" is balanced; ")(" is not.
- Substring
- A run of characters that sit next to each other in the original string. You cannot skip characters in the middle.
- Run ending here
- The length of the longest balanced substring whose last character is this one. It is 0 when this position cannot end a balanced run.
Length of the balanced run ending at each position of ")()())"
Every position starts at 0 and the best length so far is 0.
What happens in this step
s = ")()())" lengths = 0, 0, 0, 0, 0, 0 best = 0 Position 0 is left alone: a run cannot end at the first character, because there is nothing before it to open the bracket.
Steps to visualize
- The row is the 6 characters of ")()())"; the label shows the position and the character.
- Each cell holds the length of the longest balanced run that ends exactly at that character.
- An opening bracket can never end a balanced run, so those cells stay 0.
- A ) sitting right after a ( scores 2, plus whatever run ended just before the pair.
- A ) sitting after another ) looks back past that run for a matching ( and glues everything together.
- The box marks the run being measured.
- The answer is the largest number in the row.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
Every position starts at 0 and the best length so far is 0.
What happens in this step
s = ")()())" lengths = 0, 0, 0, 0, 0, 0 best = 0 Position 0 is left alone: a run cannot end at the first character, because there is nothing before it to open the bracket.
Solution
function longestValidParentheses(s) {
const lengths = new Array(s.length).fill(0);
let best = 0;
for (let i = 1; i < s.length; i += 1) {
if (s[i] !== ')') {
continue;
}
if (s[i - 1] === '(') {
lengths[i] = (i >= 2 ? lengths[i - 2] : 0) + 2;
} else {
const start = i - lengths[i - 1] - 1;
if (start >= 0 && s[start] === '(') {
lengths[i] = lengths[i - 1] + 2 + (start >= 1 ? lengths[start - 1] : 0);
}
}
if (lengths[i] > best) {
best = lengths[i];
}
}
return best;
}- Time
- O(n)
- Space
- O(n)
Test cases
| Input | Expected | Covers |
|---|---|---|
s = ")()())" | 4 | example from the description |
s = "(()" | 2 | a leftover opening bracket at the front |
s = "" | 0 | empty string |
s = ")(" | 0 | brackets in the wrong order, so nothing is balanced |
s = "()(())" | 6 | a nested run glued onto the run before it |
s = "()(()" | 2 | a valid run followed by brackets that never close |