[python] 백준 1918 - 후위표기식
백준 1918 - [Gold 2]
쉬운 문제 ?
정보처리기사에서도 Tree 자료구조를 다룰 때 후위 표기법과 트리의 후위 순회 등을 볼 수 있다.
골드 2 문제치고는 쉬운 편인 것 같다.
후위 표기법
과 stack
을 사용할 수 있다면, 금방 풀 수 있다.
SSAFY에서도 알고리즘 학습 주간에 tree
개념에 들어가기 전,
stack
자료구조를 배울 때 푸는 문제 중 하나였다.
배울 당시에는 10분도 안 걸려서 풀었는데,
이번에는 3시간 넘게 잡고 있다가 결국 못 풀고
과거의 나에게 달려가 코드 제출 내역을 확인했다.
심지어 그걸 보면서도 이해하는 데에 오래 걸렸다.
오늘 문제를 접한 시점에는
입력을 리스트로 구현한 트리에 중위 표기로 넣고,
후위 순회하여 뽑아내겠다는 생각으로 접근했는데,
내 머리가 아직 그걸 할 수 있는 단계는 아닌 것 같았다.
접근 방식 조차 기억이 안 났던 것이다…
후위 표기식이란 건
일반적으로 사용하는 중위 표기식은 컴퓨터가 읽어들이기 힘들기 때문에,
컴파일 단계에서 stack
만으로 간단히 계산할 수 있는 후위 표기식으로 변환한다고 한다.
컴퓨터는 위의 식을 어떻게 읽을 수 있을까?
처음 등장한 + 에서 A와 B를 더해버리면 B*C 단계에서 문제가 생긴다.
무조건 +가 등장한다고 뒤의 것을 더해선 안 되고, 그 뒤의 부호 까지 확인해야 하는 것이다.
과연 고귀하신 컴퓨터님께서 그런 귀찮은 작업을 해야할까?
위의 중위 표기식을 후위 표기식으로 바꾸면 아래와 같다.
\[A B C \times D \div + E +\]후위 표기식을 계산하는 방법은 다음과 같다.
식의 앞부터 읽어나가며 수(위의 알파벳)이 나올 경우
Stack
에 넣는다.stack = [A, B, C]
라고 가정하자.만약 부호가 등장하면, 스택에서 두 개의 값을 가져온 뒤 해당 부호로 연산하여 다시 값을 넣는다.
곱연산 기호를 만나 B와 C를 가져와 BC로 만들고 다시 스택에 넣을 경우,
stack = [A, BC]
식이 끝날 때까지 1과 2를 반복한다!
이 경우, 컴퓨터는 당장에 읽은 수와 부호만 처리하면 된다!
스택의 변화를 나열해보자면,
ABC
[A, B, C] *
[A, BC] D
[A, BC, D] /
[A, BC/D] +
[A+BC/D] E
[A+BC/D, E] +
[A+BC/D+E]
결과 : A+B*C/D+E
이렇게 변화하여, 마지막에는 중위 표기식으로 돌아오게 되는 것이다!
알파벳 대신 수를 넣어서 계산한다면 정답이 바로 등장한다.
후위 표기로 만들기
문제 조건
A * B가 AB로 표현되는 일은 없으며,
사용되는 기호는 + - / * ( ) 여섯 개가 끝이며,
피연산자는 A ~ Z 까지의 알파벳이다.
사칙연산 네 개만 있다면 코드가 훨씬 짧아지겠지만, 괄호가 있어 따로 처리해줘야 한다.
괄호 안은 바깥의 식과 독립되기 때문에, 회귀로 들어가서 처리할 수도 있을 것이다.
일단은 전역환경에서 후위 표기식 담을 str형 변수 result
와 stack
하나만 사용하여 풀어보자.
풀이 과정
피연산자(알파벳, 수)를 만나면
result
에 담는다.연산자를 만나면 종류를 판별한다.
2-1. 만약
stack
이 비어있다면, 종류 불문 일단 넣는다.괄호의 경우
3-1.
(
여는 괄호일 경우, 무조건stack
에 넣고 넘어가면 된다.이는 새로운 계를 여는 셈이므로, 하나의 기준이 된다.
3-2.
)
닫는 괄호의 경우, 해당 계를 닫는 상황이므로여는 괄호가 나올 때까지 값들을 전부
pop
해서result
에 붙여준다.곱연산, 나눗셈의 경우
4-1.
top
값이 곱연산, 나눗셈인 경우,stack
을pop
하여result
에 붙여준다.top
이 곱 또는 나눗셈이어야 하는 이유는 다음과 같다.top = +
,일 때, 현재 처리하는 기호가/
인데 만약+
를 처리해버리면,A+B/C
에서,/
보다+
를 먼저 처리하는 것이므로, 연산 순서가 맞지 않는다.top = *
로 가정하면,A*B/C
이므로 처리에 문제가 없는 것이다.현재 검사 중인 기호의 다음에 올 수 또는 기호를 알 수 없기 때문에
이미 스택에 들어간 이전 기호에 대해서만 처리를 할 수 있다.
4-2. 그 다음 현재 처리 중인 기호를
stack
에 넣어준다.(append)
4-3.
top
이 합차(+,-) 연산인 경우, 위의 설명에 따라 넘어간다.덧셈, 뺄셈 (합차)의 경우
5-1.
top
의 연산자 종류에 불문하고,현재 계가 끝날 때까지
stack
을pop
하여result
에 붙이는 걸 반복한다.5-2.
+, -
는 연산 순서의 마지막이기 때문에, 앞에 존재하는 연산을 모두 처리해도 상관 없다.A-B/C+D
에서, 현재+
를 처리한다고 가정하자.result = ABC
,stack = [-, /]
이다.처리해야 하는 연산은
+
기준 좌변이므로 모두 연산 순서가+
보다 빠르다. 이는stack
의top
이+, -
여도 변함이 없다.그렇게 현재 계의 연산을 모두 처리하고, 현재 처리 중인 기호를 넣으면 된다.
stack
에 남은 연산자를pop
하여result
에 붙인다.
정답 코드
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
S = sys.stdin.readline()
stack = []
result = ''
for i in S:
if i.isalpha():
result += i
else:
if not stack:
stack.append(i)
elif i == '(':
stack.append(i)
elif i == ')':
while stack and stack[-1] != '(': # 계를 끝낼 때까지
result += stack.pop()
stack.pop()
elif i in '/*':
while stack and stack[-1] in '/*': # stack top이 곱, 나눗셈인 경우
result += stack.pop()
stack.append(i)
elif i in '+-':
while stack and stack[-1] != '(': # 현재 계가 끝날 때까지
result += stack.pop()
stack.append(i)
while stack:
result += stack.pop()
print(result)