Maybe it's helpful to look in a simple case of the problem:
n = 2
(())
()()
So we start by n=2
and we produce a sequence of (
n times followed by a sequence of )
n times and we return a list of that. Then we recursively do that with n-1. When we reach n=1
it looks like we reached the base case which is that we need to return a string with ()
n times (not n=1 but n=2).
n = 3
((()))
(())()
()()()
Same pattern for n=3
.
The above examples are helpful to understand how the problem can be solved recursively.
def legal_parentheses(n, nn=None):
if nn == 1:
return ["()" * n]
else:
if not nn:
nn = n
# This will produce n ( followed by n ) ( i.e n=2 -> (()) )
string = "".join(["(" * nn, ")" * nn])
if nn < n:
# Then here we want to produce () n-nn times.
string += "()" * (n-nn)
return [string] + legal_parentheses(n, nn-1)
print(legal_parentheses(3))
print(legal_parentheses(4))
print(legal_parentheses(5))
For n = 3:
['((()))', '(())()', '()()()']
For n = 4:
['(((())))', '((()))()', '(())()()', '()()()()']
For n = 5:
['((((()))))', '(((())))()', '((()))()()', '(())()()()', '()()()()()']
This is one way of solving the problem.
The way to think about solving a problem recursively, in my opinion, is to first pick the simplest example of your problem in your case, n=2
and then write down what do you expect as a result. In this case, you are expecting the following output:
"(())", "()()"
Now, you are trying to find a strategy to break down the problem such that you can produce each of the strings. I start by thinking of the base case. I say the trivial case is when the result is ()()
, I know that an element of that result is just ()
n times. If n=2
, I should expect ()()
and when n=3
I should expect ()()()
and there should be only one such element in the sequence (so it should be done only once) hence it becomes the base case. The question is how do we calculate the (())
part of the result. The patterns shows that we just have to put n
(
followed by n
)
-> (())
for n=2
. This looks like a good strategy. Now you need to start thinking for a slightly harder problem and see if our strategy still holds.
So let's think of n=3
. What do we expect as a result?
'((()))', '(())()', '()()()'
Ok, we see that the base case should still produce the ()()()
part, all good, and should also produce the ((()))
part. What about the (())()
part? It looks like we need a slightly different approach. In this case, we need to somehow generate n (
followed by n )
and then produce n-1
(
followed by n-1
)
and then n-2
(
followed by n-2
)
and so on, until we reach the base case n=1
where we just going to produce ()
part n
times. But, if we were to call the function each time with n-1
then when we reach the base case we have no clue what the original n
value was and hence we cannot produce the ()
part as we don't know how many we want (if original n
was 3 then we need ()()()
but if we change n
by calling the function with n-1
then by the time we reach the base case, we won't know the original n
value). Hence, because of that, in my solution, I introduce a second variable called nn
that is the one that is reduced each time, but still, we leave the n
unmodified so we know what the original value was.