The "Maximum Nesting Depth of Two Valid Parentheses Strings" problem asks you to take a valid parentheses string seq
(a string consisting only of '(' and ')' that is balanced and properly nested), and split it into two disjoint valid parentheses subsequences A
and B
. Each parenthesis in seq
must be assigned to either A
or B
, and every parenthesis is assigned to exactly one of them.
The goal is to assign each parenthesis in seq
to A
or B
such that the maximum nesting depth between A
and B
is minimized. The output should be an array of integers of the same length as seq
, where the i
-th element is 0 if the i
-th parenthesis is assigned to A
and 1 if assigned to B
.
Constraints:
A
or B
.A
and B
will be valid parentheses strings.A
and B
.When first approaching this problem, you might think about generating all possible assignments and checking which one minimizes the maximum depth. However, this brute-force approach is computationally expensive and not practical for larger inputs.
Instead, we can look for patterns in how nesting depth works. The key insight is that the depth of a parenthesis at position i
depends on how many open parentheses have not yet been closed at that point. If we alternate assigning parentheses at increasing depths, we can "split" the deep nestings between A
and B
to keep their maximum depths as balanced as possible.
This leads to the idea of assigning parentheses based on their current depth: for example, if the current depth is even, assign to A
; if odd, assign to B
(or vice versa).
Here’s how we can implement the optimized solution step by step:
depth
to 0. As you iterate through seq
, increment depth
when you see '(', and decrement when you see ')'.
depth
after processing, and assign it to depth % 2
(or 1 - (depth % 2)
depending on convention).depth % 2
before decrementing depth (because the closing parenthesis corresponds to the same nesting level as its matching open).A
or B
such that both subsequences remain valid and the maximum depth is minimized.
This method ensures that at every nesting level, the parentheses are distributed as evenly as possible between A
and B
.
Let's take seq = "(()())"
as an example.
depth = 0
and an empty result array.
1
(since depth is now 1), result = [1]0
(depth is 2), result = [1,0]0
(depth is 2), then decrement depth to 1, result = [1,0,0]0
, result = [1,0,0,0]0
(depth is 2), then decrement depth to 1, result = [1,0,0,0,0]1
(depth is 1), then decrement depth to 0, result = [1,0,0,0,0,1][1,0,0,0,0,1]
. This means that the first and last parentheses are assigned to B
, and the rest to A
, resulting in both subsequences having a maximum depth of 1.
class Solution:
def maxDepthAfterSplit(self, seq: str) -> list[int]:
res = []
depth = 0
for c in seq:
if c == '(':
depth += 1
res.append(depth % 2)
else:
res.append(depth % 2)
depth -= 1
return res
class Solution {
public:
vector<int> maxDepthAfterSplit(string seq) {
vector<int> res;
int depth = 0;
for (char c : seq) {
if (c == '(') {
++depth;
res.push_back(depth % 2);
} else {
res.push_back(depth % 2);
--depth;
}
}
return res;
}
};
class Solution {
public int[] maxDepthAfterSplit(String seq) {
int n = seq.length();
int[] res = new int[n];
int depth = 0;
for (int i = 0; i < n; ++i) {
if (seq.charAt(i) == '(') {
depth++;
res[i] = depth % 2;
} else {
res[i] = depth % 2;
depth--;
}
}
return res;
}
}
var maxDepthAfterSplit = function(seq) {
let res = [];
let depth = 0;
for (let c of seq) {
if (c === '(') {
depth++;
res.push(depth % 2);
} else {
res.push(depth % 2);
depth--;
}
}
return res;
};
Brute-force approach:
seq
), and checking validity and depth for each, leading to O(2^n) time complexity.
seq
exactly once, doing O(1) work for each character, so the time complexity is O(n), where n
is the length of seq
.
n
, so the space complexity is also O(n).
This is optimal for this problem, as we must examine every character at least once.
The key insight for this problem is to distribute parentheses between two groups in such a way that their maximum nesting depths are balanced. By assigning parentheses based on the parity (even/odd) of their depth, we ensure that both groups remain valid and their depths are as close as possible. This leads to an efficient O(n) solution that is elegant, simple, and easy to implement.