coding test

[파이썬] 4874. Forth

잔망루피 2021. 1. 14. 20:06

출처 : swexpertacademy.com/main/learn/course/lectureProblemViewer.do

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

※ SW Expert 아카데미의 문제를 무단 복제하는 것을 금지합니다.


Forth라는 컴퓨터 언어는 스택 연산을 기반으로 하고 있어 후위 표기법을 사용한다. 예를 들어 3+4는 다음과 같이 표기한다.

3 4 + .
 

Forth에서는 동작은 다음과 같다.
 

숫자는 스택에 넣는다.

연산자를 만나면 스택의 숫자 두 개를 꺼내 더하고 결과를 다시 스택에 넣는다.

‘.’은 스택에서 숫자를 꺼내 출력한다.

 

Forth 코드의 연산 결과를 출력하는 프로그램을 만드시오. 만약 형식이 잘못되어 연산이 불가능한 경우 ‘error’를 출력한다.
 

다음은 Forth 연산의 예이다.
 

코드

출력

4 2 / .

2

4 3 - .

1

 
 

[입력]
 

첫 줄에 테스트 케이스 개수 T가 주어진다.  1T50
 

다음 줄부터 테스트 케이스의 별로 정수와 연산자가 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