Maximum Nesting Depth of the Parentheses
Description
You are given a valid parentheses string (VPS) s. The string may contain digits (0-9), operators (+, -, *, /), and parentheses ((, )).
A VPS is defined recursively:
- An empty string
""is a VPS. - If
Ais a VPS, then"(" + A + ")"is a VPS. - If
AandBare both VPS, thenA + Bis a VPS.
The nesting depth of a VPS is defined as:
depth("") = 0depth(A + B) = max(depth(A), depth(B))depth("(" + A + ")") = 1 + depth(A)
In simpler terms, the nesting depth is the maximum number of nested (concentric) opening parentheses at any point in the string. Your task is to return this maximum nesting depth.
Examples
Example 1
Input: s = "(1+(2*3)+((8)/4))+1"
Output: 3
Explanation: The digit 8 is wrapped inside three layers of parentheses: the outermost (...), then ((...)), then (((...))). No other part of the expression is nested deeper than 3 levels.
Example 2
Input: s = "(1)+((2))+(((3)))"
Output: 3
Explanation: The digit 3 is inside three nested parentheses: (((3))). The digit 2 is only inside two nested parentheses ((2)), and the digit 1 is inside just one. The maximum is 3.
Example 3
Input: s = "()(())((()()))"
Output: 3
Explanation: The deepest nesting occurs inside ((()())) where the inner () pairs sit at depth 3.
Constraints
- 1 ≤ s.length ≤ 100
- s consists of digits
0-9and characters+,-,*,/,(, and) - It is guaranteed that
sis a valid parentheses string (VPS)
Editorial
Brute Force
Intuition
The most natural way to think about nesting depth is to use a stack. Every time we see an opening parenthesis (, we push it onto the stack. Every time we see a closing parenthesis ), we pop from the stack. The size of the stack at any moment tells us the current nesting depth — because the stack holds all the unmatched opening parentheses that surround our current position.
Think of it like walking into nested rooms in a building. Each ( is a door you walk through (entering a deeper room), and each ) is a door you walk back out of. The maximum number of rooms deep you ever reach is the answer. The stack keeps track of all the doors you've walked through but haven't exited yet.
Step-by-Step Explanation
Let's trace through with s = "(1+(2*3)+((8)/4))+1":
Step 1: Initialize an empty stack and max_depth = 0.
Step 2: s[0] = '(' → Push onto stack. Stack: ['(']. Size = 1. max_depth = max(0, 1) = 1.
Step 3: s[1] = '1' → Not a parenthesis, skip.
Step 4: s[2] = '+' → Not a parenthesis, skip.
Step 5: s[3] = '(' → Push. Stack: ['(', '(']. Size = 2. max_depth = max(1, 2) = 2.
Step 6: s[4..6] = '2*3' → Skip non-parenthesis characters.
Step 7: s[7] = ')' → Pop. Stack: ['(']. Size = 1.
Step 8: s[8] = '+' → Skip.
Step 9: s[9] = '(' → Push. Stack: ['(', '(']. Size = 2. max_depth = max(2, 2) = 2.
Step 10: s[10] = '(' → Push. Stack: ['(', '(', '(']. Size = 3. max_depth = max(2, 3) = 3.
Step 11: s[11] = '8' → Skip.
Step 12: s[12] = ')' → Pop. Stack: ['(', '(']. Size = 2.
Step 13: s[13] = '/' → Skip.
Step 14: s[14] = '4' → Skip.
Step 15: s[15] = ')' → Pop. Stack: ['(']. Size = 1.
Step 16: s[16] = ')' → Pop. Stack: []. Size = 0.
Step 17: s[17] = '+' → Skip.
Step 18: s[18] = '1' → Skip.
Result: max_depth = 3.
Stack-Based Nesting Depth — Push on '(', Pop on ')' — Watch how the stack grows each time we enter a nested parenthesis and shrinks when we exit. The maximum stack size at any point is the answer.
Algorithm
- Initialize an empty stack and
max_depth = 0 - For each character
cin the string:- If
c == '(': push it onto the stack; updatemax_depth = max(max_depth, stack.size()) - If
c == ')': pop from the stack - Otherwise: skip (it's a digit or operator)
- If
- Return
max_depth
Code
#include <stack>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
int maxDepth(string s) {
stack<char> stk;
int maxDepth = 0;
for (char c : s) {
if (c == '(') {
stk.push(c);
maxDepth = max(maxDepth, (int)stk.size());
} else if (c == ')') {
stk.pop();
}
}
return maxDepth;
}
};class Solution:
def maxDepth(self, s: str) -> int:
stack = []
max_depth = 0
for c in s:
if c == '(':
stack.append(c)
max_depth = max(max_depth, len(stack))
elif c == ')':
stack.pop()
return max_depthimport java.util.Stack;
class Solution {
public int maxDepth(String s) {
Stack<Character> stack = new Stack<>();
int maxDepth = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
stack.push(c);
maxDepth = Math.max(maxDepth, stack.size());
} else if (c == ')') {
stack.pop();
}
}
return maxDepth;
}
}Complexity Analysis
Time Complexity: O(n)
We scan the string once, performing O(1) work per character (push, pop, or skip). Total: O(n) where n is the length of the string.
Space Complexity: O(n)
In the worst case, a string like "(((())))" would push n/2 elements onto the stack before any pops. The stack therefore uses O(n) space.
Why This Approach Is Not Efficient
The stack-based solution is already O(n) in time, which is optimal since we must read every character. However, the O(n) space for the stack is unnecessary.
Notice what we actually use the stack for: we never inspect which specific characters are stored — we only care about the size of the stack. Every push increments the size, every pop decrements it. This is just a counter!
If we replace the entire stack with a single integer variable that tracks the current depth, we get the exact same result with O(1) space. The stack was overkill — an integer counter is all we need.
Optimal Approach - Counter Variable
Intuition
Since we only ever need the stack's size (never its actual contents), we can replace the entire stack with a single integer depth. Increment depth when we see (, decrement when we see ). Track the maximum value depth ever reaches.
This is like counting floors in an elevator. Going up one floor when you enter a (, going down one floor when you hit a ). The highest floor you ever visit is the maximum nesting depth. You don't need to remember every floor you visited (the stack) — just the current floor number (the counter).
Step-by-Step Explanation
Let's trace through with s = "(1+(2*3)+((8)/4))+1":
Step 1: depth = 0, max_depth = 0.
Step 2: s[0] = '(' → depth = 1. max_depth = max(0, 1) = 1.
Step 3: s[1] = '1' → skip. depth stays 1.
Step 4: s[2] = '+' → skip. depth stays 1.
Step 5: s[3] = '(' → depth = 2. max_depth = max(1, 2) = 2.
Step 6: s[4..6] = '2*3' → skip. depth stays 2.
Step 7: s[7] = ')' → depth = 1. max_depth stays 2.
Step 8: s[8] = '+' → skip.
Step 9: s[9] = '(' → depth = 2. max_depth stays 2.
Step 10: s[10] = '(' → depth = 3. max_depth = max(2, 3) = 3.
Step 11: s[11] = '8' → skip.
Step 12: s[12] = ')' → depth = 2.
Step 13: s[13..14] = '/4' → skip.
Step 14: s[15] = ')' → depth = 1.
Step 15: s[16] = ')' → depth = 0.
Step 16: s[17..18] = '+1' → skip.
Result: max_depth = 3.
Counter-Based Depth Tracking — O(1) Space — Watch the depth counter rise and fall as we scan through the expression. The maximum value it reaches is the nesting depth — no stack needed.
Algorithm
- Initialize
depth = 0andmax_depth = 0 - For each character
cin the string:- If
c == '(': incrementdepth, then updatemax_depth = max(max_depth, depth) - If
c == ')': decrementdepth - Otherwise: skip (digit or operator)
- If
- Return
max_depth
Code
class Solution {
public:
int maxDepth(string s) {
int depth = 0;
int maxDepth = 0;
for (char c : s) {
if (c == '(') {
depth++;
maxDepth = max(maxDepth, depth);
} else if (c == ')') {
depth--;
}
}
return maxDepth;
}
};class Solution:
def maxDepth(self, s: str) -> int:
depth = 0
max_depth = 0
for c in s:
if c == '(':
depth += 1
max_depth = max(max_depth, depth)
elif c == ')':
depth -= 1
return max_depthclass Solution {
public int maxDepth(String s) {
int depth = 0;
int maxDepth = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
depth++;
maxDepth = Math.max(maxDepth, depth);
} else if (c == ')') {
depth--;
}
}
return maxDepth;
}
}Complexity Analysis
Time Complexity: O(n)
We scan the string exactly once, performing O(1) work per character (one comparison, one increment or decrement, and one max comparison). Total: O(n).
Space Complexity: O(1)
We use only two integer variables (depth and max_depth) regardless of input size. This is a significant improvement over the O(n) stack space from the brute force approach.
This solution is optimal in both time and space: O(n) time is necessary because we must read every character, and O(1) space is the minimum possible for any in-place traversal.