Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Maximum Nesting Depth of Two Valid Parentheses Strings in Python
A Valid Parentheses String (VPS) consists only of "(" and ")" characters and satisfies specific structural properties. The goal is to split a VPS into two disjoint subsequences A and B such that the maximum nesting depth is minimized.
Understanding Valid Parentheses Strings
A string is a Valid Parentheses String if ?
It is the empty string, or
It can be written as AB, where A and B are VPS's, or
It can be written as (A), where A is a VPS.
Nesting Depth Definition
The nesting depth of a VPS is defined recursively ?
depth("") = 0
depth(A + B) = max of depth(A), depth(B), where A and B are VPS's
depth("(" + A + ")") = 1 + depth(A), where A is a VPS
Algorithm Approach
The strategy is to balance the parentheses between two groups to minimize the maximum depth. We maintain two counters c1 and c2 representing the current depth of groups A and B ?
For opening parentheses: assign to the group with smaller current depth
For closing parentheses: assign to the group with larger current depth
Implementation
class Solution:
def maxDepthAfterSplit(self, seq):
n = len(seq)
result = [0] * n
c1, c2 = 0, 0 # Counters for group A and B depths
for i in range(n):
if seq[i] == '(':
if c1 < c2:
c1 += 1
# result[i] remains 0 (group A)
else:
c2 += 1
result[i] = 1 # group B
else: # seq[i] == ')'
if c1 > c2:
c1 -= 1
# result[i] remains 0 (group A)
else:
c2 -= 1
result[i] = 1 # group B
return result
# Test the solution
solution = Solution()
test_string = "()(())()"
result = solution.maxDepthAfterSplit(test_string)
print(f"Input: {test_string}")
print(f"Output: {result}")
Input: ()(())() Output: [0, 0, 0, 1, 0, 1, 0, 0]
How It Works
Let's trace through the example "()(())()" step by step ?
def trace_algorithm(seq):
n = len(seq)
result = [0] * n
c1, c2 = 0, 0
print(f"Processing: {seq}")
print("i | char | c1 | c2 | result[i] | action")
print("-" * 40)
for i in range(n):
char = seq[i]
if char == '(':
if c1 < c2:
c1 += 1
action = "assign to A"
else:
c2 += 1
result[i] = 1
action = "assign to B"
else: # char == ')'
if c1 > c2:
c1 -= 1
action = "close A"
else:
c2 -= 1
result[i] = 1
action = "close B"
print(f"{i} | {char} | {c1} | {c2} | {result[i]} | {action}")
return result
trace_algorithm("()(())()")
Processing: ()(())() i | char | c1 | c2 | result[i] | action ---------------------------------------- 0 | ( | 1 | 0 | 0 | assign to A 1 | ) | 0 | 0 | 0 | close A 2 | ( | 1 | 0 | 0 | assign to A 3 | ( | 1 | 1 | 1 | assign to B 4 | ) | 1 | 0 | 1 | close B 5 | ) | 0 | 0 | 0 | close A 6 | ( | 1 | 0 | 0 | assign to A 7 | ) | 0 | 0 | 0 | close A
Key Points
The algorithm ensures balanced distribution of parentheses between two groups
Time complexity: O(n) where n is the length of the string
Space complexity: O(n) for the result array
The result array encodes group assignment: 0 for group A, 1 for group B
Conclusion
This algorithm efficiently splits a valid parentheses string into two subsequences while minimizing the maximum nesting depth. The greedy approach of always assigning to the group with smaller depth ensures optimal distribution.
