올바른 괄호란 (())나 ()와 같이 올바르게 모두 닫힌 괄호를 의미합니다. )(나 ())() 와 같은 괄호는 올바르지 않은 괄호가 됩니다. 괄호 쌍의 개수 n이 주어질 때, n개의 괄호 쌍으로 만들 수 있는 모든 가능한 괄호 문자열의 갯수를 반환하는 함수 solution을 완성해 주세요.
n번째 올바른 괄호의 개수를 n-1번째 괄호의 개수에서 도출하는 방법부터 생각해 보자. 우선 n = 3일때를 생각해 본다면, 2개의 괄호쌍의 개수는 ()(), (()) 가 될 것이다.
총 괄호의 개수가 n이라면, 1~n-1의 케이스의 조합으로 나타낼 수 있다는 사실은 자명하다. 여기서 우리는 직관적으로, n-1개의 괄호 양 쪽에 괄호를 세우거나 ((())), (()()) 혹은 왼쪽, 오른쪽에 괄호를 세우는 경우 ()(()), (())(), ()()()를 생각해 볼 수 있을 것이다. 실제 n=3일때 역시 총 개수는 5가 되므로 옳은 경우이다. 하지만 n이 4일때는? (())(())와 같은 케이스는 위 알고리즘으로 해결할 수 없다. n=2일때의 경우 (())를 이어붙인 케이스이기 때문이다. 또한 중복 역시 걸러낼 수 없는데, ()()() + () 의 결과와 () + ()()()의 결과는 동일하기 때문이다.
n개의 괄호로 나타낼 수 있는 개수를 Cn이라고 둔다면, Cn = f(C1, Cn-1) + f(C2, Cn-2) ... f(Cn-1, C1)꼴로 나타나게 된다. 여기서 함수 f를 왼쪽 Ck 양쪽에 괄호를 세우는 경우의 수로 정의해보자. 이 때, 괄호 하나가 추가되는 꼴이므로 왼쪽의 idx를 재조정하고 고려해야 항을 더 추가한다. 바뀐 식은 다음과 같다 :
으로 모든 경우의 수를 고려할 수 있다는 사실을 만족한다. 중복 처리, 1 .. n-1의 경우의 수를 모두 고려한다는 제약 조건 역시 동일하다. 여기서 초기항 C0이 등장하였는데, 빈 공간이긴 하지만 곱셈 연산을 위해 1로 초기화한다는 점을 고려하자. 따라서 위 식은 최종적으로 다음과 같아진다.
Cn = C0*Cn-1 + C1*Cn-1 + .... + Cn-1*C0
이렇게 정의되는 수열이 카탈란 수열이 된다. 카탈란 수열은 이외에도 계산 순서 구하기, 이진 트리, 삼각형 개수 구하기 등 개수를 구하는 많은 문제의 해답이 될 수 있다고 한다! 아래 블로그를 참조하였음을 밝혀 둔다.