Solution: Generate Parentheses

Let's solve the Generate Parentheses problem using the Subsets pattern.

Statement#

For a given number, n, generate all combinations of balanced parentheses.

Constraints:

  • 11 \leq n 10\leq 10

Solution#

Problems where we require constructing multiple valid answers, such as permutation of any nn number or generating a long list of nn pairs of balanced parentheses, are good examples to solve using the subsets pattern.

To solve this problem using the subsets pattern, we use a recursive algorithm. The purpose of this algorithm is to correctly generate all of the possible subsets of the parentheses combination.

The key observation in constructing the solution is to keep track of the number of opening, (, and closing, ), parentheses. We’ll use this count to add parentheses in a way that keeps the sequence balanced and valid.

  • We only add an opening parenthesis if there is still one to add.

  • We only add a closing parenthesis if the number of closing parentheses does not exceed the number of opening parentheses.

The basic algorithm is as follows:​

  1. Create a list to store all possible combinations of parentheses.
  2. Call the back_track function for n pairs of parentheses, count of left parentheses, count of right parentheses, an empty list for output, and an empty list for the result.
  3. If the count of opening and closing parentheses equals n, then we have a valid combination of parentheses, so we will append the string to our list.
  4. Otherwise, we will check if the number of opening parentheses is less than n. If yes, we will add opening parentheses to our string and increment the count.
  5. Lastly, we will check the count of closing parentheses. If the count is less than the count of opening parentheses, then we will add closing parentheses to our string and increment its count.

Let’s see how this algorithm works for an example, where n=3n=3:

Created with Fabric.js 3.6.6 Output top - Initially, our stack is empty.We will use left count to keep track of the openingbraces and right count to keep track of the closing braces.

1 of 44

Created with Fabric.js 3.6.6 - ( ( Output top n = 3, left count = 0, right count = 0left count < noutput.push('(')

2 of 44

Created with Fabric.js 3.6.6 - ( ( (( ( Output top n = 3, left count = 1, right count = 0left count < noutput.push('(')

3 of 44

Created with Fabric.js 3.6.6 - ( ( ( ((( (( ( Output top n = 3, left count = 2, right count = 0left count < noutput.push('(')

4 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ((() ((( (( ( Output top n = 3, left count = 3, right count = 0right count < left countoutput.push(')')

5 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ((()) ((() ((( (( ( Output top n = 3, left count = 3, right count = 1right count < left countoutput.push(')')

6 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ((())) ((()) ((() ((( (( ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.push(')')

7 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ((())) ((())) ((()) ((() ((( (( ( Output top This is the first combinationof braces printed by theabove recursions. n = 3, left count = 3, right count = 3left count == n && right count == nprint(output)

8 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ((())) ((()) ((() ((( (( ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.pop()

9 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ((())) ((() ((( (( ( Output top n = 3, left count = 3, right count = 1right count < left countoutput.pop()

10 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ((())) ((( (( ( Output top n = 3, left count = 3, right count = 0right count < left countoutput.pop()

11 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) (() (( ( Output top n = 3, left count = 2, right count = 0left count < noutput.pop()right count < left countoutput.push(')')

12 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( (()( (() (( ( Output top n = 3, left count = 2, right count = 1left count < noutput.push('(')

13 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) (()() (()( (() (( ( Output top n = 3, left count = 3, right count = 1right count < left countoutput.push(')')

14 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) (()()) (()() (()( (() (( ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.push(')')

15 of 44

Created with Fabric.js 3.6.6 This is the second combination of braces printed byabove recursions. - ( ( ( ) ) ) ) ((())) ( ) ) (()()) (()()) (()() (()( (() (( ( Output top n = 3, left count = 3, right count = 3left count == n && right count == nprint(output)

16 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) (()()) (()() (()( (() (( ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.pop()

17 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) (()()) (()( (() (( ( Output top n = 3, left count = 3, right count = 1right count < left countoutput.pop()

18 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) (()) (() (( ( Output top n = 3, left count = 2, right count = 1left count < noutput.pop()right count < left countoutput.push(')')

19 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( (())) (()) (() (( ( Output top n = 3, left count = 2, right count = 2left count < noutput.push('(')

20 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() (())) (()) (() (( ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.push(')')

21 of 44

Created with Fabric.js 3.6.6 This is the third combination of braces printed by above recursions. - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() (())() (())) (()) (() (( ( Output top n = 3, left count = 3, right count = 3left count == n && right count == nprint(output)

22 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() (())( (()) (() (( ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.pop()

23 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() (()) (() (( ( Output top n = 3, left count = 2, right count = 2left count < noutput.pop()

24 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() (() (( ( Output top n = 3, left count = 2, right count = 1right count < left countoutput.pop()

25 of 44

Created with Fabric.js 3.6.6 - ( ( ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() (( ( Output top n = 3, left count = 2, right count = 0right count < left countoutput.pop()

26 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() () ( Output top n = 3, left count = 1, right count = 0left count < noutput.pop()right count < left countoutput.push(')')

27 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ()( () ( Output top n = 3, left count = 1, right count = 1left count < noutput.push('(')

28 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ()(( ()( () ( Output top n = 3, left count = 2, right count = 1left count < noutput.push('(')

29 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ()(() ()(( ()( () ( Output top n = 3, left count = 3, right count = 1right count < left countoutput.push(')')

30 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ()(()) ()(() ()(( ()( () ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.push(')')

31 of 44

Created with Fabric.js 3.6.6 This is the fourth combination of braces printed byabove recursions. - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ()(()) ()(()) ()(() ()(( ()( () ( Output top n = 3, left count = 3, right count = 3left count == n && right count == nprint(output)

32 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ()(()) ()(() ()(( ()( () ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.pop()

33 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ()(()) ()(( ()( () ( Output top n = 3, left count = 3, right count = 1right count < left countoutput.pop()

34 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ()() ()( () ( Output top n = 3, left count = 2, right count = 1left count < noutput.pop()right count < left count output.push(')')

35 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ()()( ()() ()( () ( Output top n = 3, left count = 2, right count = 2left count < noutput.push('(')

36 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() ()()( ()() ()( () ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.push(')')

37 of 44

Created with Fabric.js 3.6.6 This is the fifth combination of braces printed byabove recursions. - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() ()()() ()()( ()() ()( () ( Output top n = 3, left count = 3, right count = 3left count == n && right count == nprint(output)

38 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() ()()( ()() ()( () ( Output top n = 3, left count = 3, right count = 2right count < left countoutput.pop()

39 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() ()() ()( () ( Output top n = 3, left count = 2, right count = 2left count < noutput.pop()

40 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() ()( () ( Output top n = 3, left count = 2, right count = 1right count < left countoutput.pop()

41 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() () ( Output top n = 3, left count = 1, right count = 1left count < noutput.pop()

42 of 44

Created with Fabric.js 3.6.6 - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() ( Output top n = 3, left count = 1, right count = 0right count < left countoutput.pop()

43 of 44

Created with Fabric.js 3.6.6 Output top - ( ( ) ( ) ) ) ) ((())) ( ) ) ) (()()) ( ) (())() ( ( ) ) ) ()(()) ( ) ()()() n = 3, left count = 0, right count = 0right count < left countoutput.pop()stack is EMPTY, so recursion ends here.

44 of 44

Let’s look at the code for this solution below:

Generate Parentheses

Time complexity#

As visualized in the slides above, it’s easier to understand the problem by creating a tree. Given a tree with branching of bb and a maximum depth of mm, the maximum number of nodes in this tree would be the following:

1+b+b2+...+b(m1)1 + b + b^2 + ... + b^{(m-1)}

This is the sum of a geometric sequence, which evaluates to the following:

(1bm)(1b)\frac{(1- b ^ m)}{(1-b)}

So, we can say that time complexity is O(bm)O(b ^ m).

For our problem here, the following is true:

  • There is a branching of 22 because we only add an opening or a closing brace at each step.

  • There is a maximum depth of 2n2n because the length of the output is the sum of nn opening and nn closing parentheses.

This leads us to a time complexity of O(2(2n))O(2^{(2n)}), that is, O(4n)O(4^n).


Note: This is not the tightest bound on time complexity because our algorithm rejects invalid combinations, significantly saving time. Without going into the proof, which is beyond the scope of this course, we’ll note that the upper bound on the time complexity of this solution is O(4nn)O(\frac{4^n}{\sqrt{n}}).


Space complexity#

The space complexity of this solution is O(n)O(n), since the maximum size of the stack is 2n2n.

Generate Parentheses

Final Remarks