출처 : swexpertacademy.com/main/learn/course/lectureProblemViewer.do
※ SW Expert 아카데미의 문제를 무단 복제하는 것을 금지합니다.
Forth라는 컴퓨터 언어는 스택 연산을 기반으로 하고 있어 후위 표기법을 사용한다. 예를 들어 3+4는 다음과 같이 표기한다.
3 4 + .
Forth에서는 동작은 다음과 같다.
숫자는 스택에 넣는다.
연산자를 만나면 스택의 숫자 두 개를 꺼내 더하고 결과를 다시 스택에 넣는다.
‘.’은 스택에서 숫자를 꺼내 출력한다.
Forth 코드의 연산 결과를 출력하는 프로그램을 만드시오. 만약 형식이 잘못되어 연산이 불가능한 경우 ‘error’를 출력한다.
다음은 Forth 연산의 예이다.
코드 |
출력 |
4 2 / . |
2 |
4 3 - . |
1 |
[입력]
첫 줄에 테스트 케이스 개수 T가 주어진다. 1≤T≤50
다음 줄부터 테스트 케이스의 별로 정수와 연산자가 256자 이내의 연산코드가 주어진다. 피연산자와 연산자는 여백으로 구분되어 있으며, 코드는 ‘.’로 끝난다.
나눗셈의 경우 항상 나누어 떨어진다.
[출력]
#과 1번부터인 테스트케이스 번호, 빈칸에 이어 계산결과를 정수로 출력하거나 또는 ‘error’를 출력한다.
입력 | 출력 |
3 10 2 + 3 4 + * . 5 3 * + . 1 5 8 10 3 4 + + 3 + * 2 + + + . |
#1 84 #2 error #3 168 |
👑 나의 풀이
T = int(input())
# 여러개의 테스트 케이스가 주어지므로, 각각을 처리합니다.
for test_case in range(1, T + 1):
Forth=list(input().split())
stack=list()
result=0
for i in Forth :
if i == '.' :
if len(stack) == 1 :
print(f"#{test_case} {result}")
break
else :
print(f"#{test_case} error")
break
if i.isdigit() : # 숫자는 스택에 넣기
stack.append(int(i))
else:
try:
if i == '+' :
result=sum(stack[-2:])
elif i == '-' :
result=stack[-2] - stack[-1]
elif i == '*' :
result=stack[-2] * stack[-1]
elif i == '/' :
result=stack[-2] // stack[-1]
stack[-2]=result
stack.pop()
except:
print(f"#{test_case} error")
break
코드 제출하니 10개 중 9개만 통과했다고 떠서 '.'이 연산이 끝나기 전에 오는 경우를 생각했다. 리스트 stack의 길이가 1일 때 계산 결과를 출력했다.
첨에는 if i == '.'내의 if조건을 Forth.index(i) == len(Forth)-1으로 줬다. 통과가 안 된다ㅋ
입력 각각은 '.'으로 끝난다면서 왜 stack의 길이를 따져야하는지 의문이 생겼다. stack에 값이 2개 이상이 남아 있을 수 있어서 그렇다. '.'이 끝이 아닌 위치에 올까봐가 아님. 그래서 '.'의 위치를 파악하는 Forth.index(i) == len(Forth)-1을 쓰면 안 되는 이유다.
숫자는 스택에 넣고 연산자를 만나면 stack[-1]과 stack[2]를 계산한다.
계산 결과를 stack[-2]에 넣고 stack[-1]을 pop한다.
연산 과정에서 에러가 생긴다면 error를 출력하고 끝낸다.
💡 다른사람 풀이
TC = int(input())
for tc in range(1, TC+1):
Data = list(input().split())
N = len(Data)
stack = []
flag = 0
# 마침표는 제외하기 위해 N-1까지 반복
for i in range(N-1):
#숫자인 경우, stack에 append
if Data[i].isdigit():
stack.append(Data[i])
else:
try: # 후위표기 계산
num2, num1 = int(stack.pop()), int(stack.pop())
if Data[i] == "+": result = num1 + num2
elif Data[i] == "-": result = num1 - num2
elif Data[i] == "/": result = num1 // num2
elif Data[i] == "*": result = num1 * num2
stack.append(str(result))
except: #에러 발생 예외 처리 예) 숫자 + 연산자 + 연산자
flag = 987654321
#예외처리 조건 (X) + Stack의 길이가 1인 경우(계산이 성공적인경우)
if flag == 0 and len(stack) == 1:
print(f'#{tc} {stack[0]}')
#예외처리 조건 (O) + stack의 길이가 2이상인 경우 ex) 숫자만 입력된 경우
elif flag == 987654321 or len(stack)>1:
print(f'#{tc} error')
나랑 비슷한 알고리즘.
stack에서 pop한 두 수를 연산한 결과를 stack에 문자열 형태로 추가한다.
예외 처리는 flag에 임의의 숫자 987654321를 넣어준다.
flag가 0이고 stack의 길이가 1이면 계산 결과를 출력한다.
flag가 987654321고 stack의 길이가 1 이상이면 error를 출력한다.
T = int(input())
for tc in range(1, T+1):
stack = []
text = input().split()
operators = {
'+': lambda x, y: y+x,
'-': lambda x, y: y-x,
'*': lambda x, y: y*x,
'/': lambda x, y: y//x
}
result = 0
for i in text:
if i == '.':
if(len(stack) > 1):
result = "error"
else:
result = stack.pop(-1)
elif i in operators.keys():
if(len(stack) < 2): # 피연산자가 2개여야해서
result = "error"
break
else:
a = int(stack.pop())
b = int(stack.pop())
result = operators[i](int(a), int(b))
stack.append(int(result))
else:
stack.append(i) # 숫자 추가
print("#%s %s" % (tc, result))
딕셔너리에 key로 연산자, value는 lambda 함수를 이용해서 구현했다. 이 부분이 정말 좋은 것 같다.
숫자를 추가하는 코드 부분이 연산하는 부분보다 위에 있으면 더 보기 편할 것 같다.
'coding test' 카테고리의 다른 글
[파이썬] 4880. 토너먼트 카드게임 (0) | 2021.01.18 |
---|---|
[파이썬] 4875. 미로 (0) | 2021.01.15 |
[파이썬] 4873. 반복문자 지우기 (0) | 2021.01.13 |
[파이썬] 4871. 그래프 경로 (0) | 2021.01.13 |
[파이썬] 4866. 괄호검사 (0) | 2021.01.12 |