Leetcode 1111. Maximum Nesting Depth of Two Valid Parentheses Strings

Problem Explanation

In this problem, we are given a valid parentheses string (a string consisting of '(' and ')' characters only). We are required to split it into two disjoint subsequences, where both the subsequences are valid parentheses strings themselves. The total length of these subsequences is equal to the length of the original string.

Our task is to choose the subsequences in such a way that the maximum depth of the nested parentheses is minimized between these subsequences.

The depth of a string depends on the parenthesis structure. For example:

  • The empty string "" has a depth of 0.
  • The strings "()()" and "()(()())" are VPS's with depths of 1 and 2 respectively.
  • The strings ")(" and "(()" are not VPS's.

We are to return an array of length equal to seq.length, to denote which characters of seq go into which subsequences. The value will be 0 if the character is part of the first subsequence and 1 if it's part of the second subsequence. If there exist multiple valid answers, we can return any.

Solution

The solution is actually quite simple and clever. We iterate over the given string and put all odd-depth parentheses in one group and all even-depth parentheses in the other group. This will effectively balance the parentheses depth between the groups.

For every opening parenthesis, we can increment the depth and for every closing parenthesis, we can decrement the depth.

To get the depth of the current parentheses, we can just use depth % 2 to get whether the depth is odd or even.

An Example

Let's walk through an example.

Given "(()())", we start with a depth of 1.

For the first opening parenthesis, increment the depth and add it to first group: [0]

For the second opening parenthesis, increment the depth and add it to the second group: [0,1]

For the first closing parenthesis, decrement the depth and add it to the second group: [0,1,1]

This process continues until the full string is traversed, ultimately yielding the result of [0,1,1,1,1,0].

Python Solution

1
2python
3class Solution:
4    def maxDepthAfterSplit(self, seq: str) -> List[int]:
5        ans = []
6        depth = 0
7
8        for c in seq:
9            if c == '(':
10                depth += 1
11                ans.append(depth % 2)
12            else:
13                ans.append(depth % 2)
14                depth -= 1
15
16        return ans

Java Solution

1
2java
3class Solution {
4    public int[] maxDepthAfterSplit(String seq) {
5        int depth = 0, n = seq.length();
6        int[] result = new int[n];
7
8        for(int i = 0; i < n; ++i) {
9            if(seq.charAt(i) == '(') {
10                depth++;
11                result[i] = depth % 2;
12            } else {
13                result[i] = depth % 2;
14                depth--;
15            }
16        }
17
18        return result;
19    }
20}

JavaScript Solution

1
2javascript
3var maxDepthAfterSplit = function(seq) {
4    let depth = 0, n = seq.length;
5    let result = new Array(n);
6
7    for(let i = 0; i < n; ++i) {
8        if(seq.charAt(i) === '(') {
9            depth++;
10            result[i] = depth % 2;
11        } else {
12            result[i] = depth % 2;
13            depth--;
14        }
15    }
16
17    return result;
18};

C++ Solution

1
2cpp
3class Solution {
4public:
5    vector<int> maxDepthAfterSplit(string seq) {
6        int depth = 0, n = seq.size();
7        vector<int> result(n);
8
9        for(int i = 0; i < n; ++i) {
10            if(seq[i] == '(') {
11                depth++;
12                result[i] = depth % 2;
13            } else {
14                result[i] = depth % 2;
15                depth--;
16            }
17        }
18
19        return result;
20    }
21};

C# Solution

1
2csharp
3public class Solution {
4    public int[] MaxDepthAfterSplit(string seq) {
5        int depth = 0, n = seq.Length;
6        int[] result = new int[n];
7
8        for(int i = 0; i < n; ++i) {
9            if(seq[i] == '(') {
10                depth++;
11                result[i] = depth % 2;
12            } else {
13                result[i] = depth % 2;
14                depth--;
15            }
16        }
17
18        return result;    
19    }
20}

Conclusion

This problem is a good example of balancing in discrete mathematics. We only need to keep track of the depth and we are able to balance the maximum depth by putting odd depths and even depths into different groups.It challenges us to find an effective way to split a given string and reveals the importance of understanding the properties of the discrete structures involved - in this case, parentheses. The solution described above demonstrates how a simple approach, based on incrementing or decrementing a 'depth' count, can be used to categorise individual parentheses into correct groups and ultimately ensure the maximum depth is minimised.

The concept of depth in this problem can be understood as the level of nesting of parentheses. When we encounter an opening parenthesis, we increase the depth because we have entered a new level of nesting. On the other hand, when we encounter closing parenthesis, we decrease the depth as we have exited a level of nesting.

The elegance of the solution lies in its simplicity and efficiency - it only involves a single pass over the string, and thus its time complexity is O(n), where n is the length of the string.

Also, its space complexity is also O(n) as we need to store the group of each character, and in the worst case scenario, the sequence might be unique for all characters in the sequence.

Overall, this problem not only presents an interesting challenge but also reveals the power and elegance of simple, efficient solutions.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫