본문 바로가기

💻 알고리즘/백준

[ 백준 ] 2504 괄호의 값 (python)

728x90

 

 

 

 

 

 

https://www.acmicpc.net/problem/2504

 

2504번: 괄호의 값

4개의 기호 ‘(’, ‘)’, ‘[’, ‘]’를 이용해서 만들어지는 괄호열 중에서 올바른 괄호열이란 다음과 같이 정의된다. 한 쌍의 괄호로만 이루어진 ‘()’와 ‘[]’는 올바른 괄호열이다.  만일

www.acmicpc.net

 

 

문제

4개의 기호 ‘(’, ‘)’, ‘[’, ‘]’를 이용해서 만들어지는 괄호열 중에서 올바른 괄호열이란 다음과 같이 정의된다.

  1. 한 쌍의 괄호로만 이루어진 ‘()’와 ‘[]’는 올바른 괄호열이다. 
  2. 만일 X가 올바른 괄호열이면 ‘(X)’이나 ‘[X]’도 모두 올바른 괄호열이 된다. 
  3. X와 Y 모두 올바른 괄호열이라면 이들을 결합한 XY도 올바른 괄호열이 된다.

예를 들어 ‘(()[[]])’나 ‘(())[][]’ 는 올바른 괄호열이지만 ‘([)]’ 나 ‘(()()[]’ 은 모두 올바른 괄호열이 아니다. 우리는 어떤 올바른 괄호열 X에 대하여 그 괄호열의 값(괄호값)을 아래와 같이 정의하고 값(X)로 표시한다. 

  1. ‘()’ 인 괄호열의 값은 2이다.
  2. ‘[]’ 인 괄호열의 값은 3이다.
  3. ‘(X)’ 의 괄호값은 2×값(X) 으로 계산된다.
  4. ‘[X]’ 의 괄호값은 3×값(X) 으로 계산된다.
  5. 올바른 괄호열 X와 Y가 결합된 XY의 괄호값은 값(XY)= 값(X)+값(Y) 로 계산된다.

예를 들어 ‘(()[[]])([])’ 의 괄호값을 구해보자. ‘()[[]]’ 의 괄호값이 2 + 3×3=11 이므로 ‘(()[[]])’의 괄호값은 2×11=22 이다. 그리고 ‘([])’의 값은 2×3=6 이므로 전체 괄호열의 값은 22 + 6 = 28 이다.

여러분이 풀어야 할 문제는 주어진 괄호열을 읽고 그 괄호값을 앞에서 정의한대로 계산하여 출력하는 것이다. 

 

입력

첫째 줄에 괄호열을 나타내는 문자열(스트링)이 주어진다. 단 그 길이는 1 이상, 30 이하이다.

 

출력

첫째 줄에 그 괄호열의 값을 나타내는 정수를 출력한다. 만일 입력이 올바르지 못한 괄호열이면 반드시 0을 출력해야 한다. 

 

예제입력 1

(()[[]])([])

 

예제출력 1

28

 

예제입력 2

[][]((])

 

예제출력 2

0

 

 

🔥 문제 풀이

 

우선 괄호의 짝 & 개수에 따라서 결과 값이 달라지는 문제라는 것을 보고 stack을 사용해야 된다 생각하고 문제를 풀어가기 시작했다.

 

괄호의 짝이 안 맞을 경우 -> ((]) 이런 경우를 걸러내는 방법

괄호의 짝이 맞은 경우 -> () or [] 이럴 때 값에 2 or 3을 더하는 방법은 어렵지 않게 풀어낼 수 있었는데

 

괄호 안의 괄호가 들어있을 때 안의 값에 곱하기 2 또는 3을 해줘야 하는 과정을 어떻게 구현해야 할지 감이 안 잡혔다.

 

그래서 처음엔 stack을 두고 열린 괄호 '('  혹은 '[' 를 만났을 땐 stack에 push 하고,

닫힌 괄호 ')' 혹은 ']' 을 만나면 열린 괄호와 함께 pop 하면서 그에 알맞은 값을 stack에 다시 append 하는 방식으로 구현을 했다.

 

ex) '(())' 

stack = ['(', '('] 인데 ')'를 만났다면 바로 stack의 마지막 값이 '(' 이기 때문에 stack에 들어있는 '(' 값을 pop 하고, ()값인 2를 다시 stack에 넣어준다.

이 과정을 마무리하고 나면 stack = ['(', 2] 이렇게 된다. 

 

이어서 ')'를 한번 더 처리할 때, stack의 탑 값인 stack[-1]이 숫자라면 stack에 들어있는 '('를 만나기 전까지 숫자 값을 모두 뽑아내서 전체 *2를 해주려고 했다.... 사실 텍스트로 설명만 해도 매우 복잡한 게 느껴지는데 구현하기에 복잡하기도 하고 분명 시간 초과가 나올 것 같아서 이 방법은 아니라고 확신했다.

 

40분 정도 붙잡고 있다가 풀이 방법을 찾지 못해서 다른 사람들의 풀이 방법을 찾아봤다.

 


 

다른 사람의 풀이 방법은 이렇다.

 

1. 열린 괄호를 만났을 때, stack에 push 해준다. 이때, tmp에 괄호에 맞는 값을 곱해준다.

ex) '(())' 을 처리할 때 처음 '('값을 stack에 push 하면서, tmp *= 2를 해준다.

 

2. 닫힌 괄호를 만났을 때, stack의 가장 최근 값이 알맞은 열린 괄호가 아닐 때 혹은 stack이 비어있을 땐 에러 처리

이 경우가 아니라면, 해당 stack의 최근 열린 괄호를 pop 하고, res값에 tmp값을 넣고 tmp에 괄호의 값을 나눠준다.

 

 ex) '(())' 열린 괄호 두 개를 만났기 때문에 현재 tmp의 값은 tmp = (tmp * 2)*2 인 상태다.

이때 ')'를 만나면 '(' 하나를 stack에서 pop 하고, res에 tmp 값을 넣어주고 tmp = tmp//2 를 해준다.

tmp 값을 다시 2로 나눠주는 이유는 이미 곱한 값을 res에 넣어줬고, pop까지 진행해줬기 때문에 나머지 괄호들을 처리할 때 더는 *2 라는 값이 필요 없기 때문이다!

 

이 두 번째 과정에서 괄호 안의 괄호를 계산해낼 수 있다.

괄호가 '(()[])' 라면 처음 괄호가 '('이기 때문에 ()과 []을 처리하는 값에 모두 *2를 해주기 때문에 전체에 *2를 해준 것과 같은 격이 된다! 

 

 

 
 

* 주의해야 할 점

stack.pop()를 진행하고 tmp값을 나누는 과정 위치를 잘 확인해야 한다.

나는 s[i - 1] == ')' 인 경우에 pop 하고 tmp값을 2로 나누면 되는 거 아닌가? 생각해서 한번 틀렸었다😥

 

'(()[[]])'인 경우로 설명을 해보자면,

마지막에 가장 밖에 있는 ')'를 처리할 때도 res에 tmp값을 더하게 되면 *2한 값을 한번 더 더해주는 격이 된다.

이미 ()[[]]을 처리하면서 *2를 해줬기 때문에 res에서 값을 넣지 않아도 된다.

 

따라서 s[i - 1] == ')' or s[i -1] == ']'인 경우에만 res에 tmp값을 더해줘야 한다!

 

 

위의 과정을 쉽게 설명해보려고 노력했는데 코드를 살펴보면 어렵지 않을 듯!

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
= input()
res = 0
tmp = 1
stack = []
 
for i in range(len(s)):
    if s[i] == '(':
        stack.append(s[i])
        tmp *= 2
 
    elif s[i] == ')':
        if not stack or stack[-1== '[':
            res = 0
            break
        if s[i - 1== '(':
            res += tmp
 
        stack.pop()
        tmp //= 2
    
    elif s[i] == '[':
        stack.append(s[i])
        tmp *= 3
 
    else:
        if not stack or stack[-1== '(':
            res = 0
            break
        if s[i - 1== '[':
            res += tmp
 
        stack.pop()
        tmp //= 3
 
if stack:
    res = 0
 
print(res)
cs

 

 

 

728x90