오늘은 3일 차 문제를 풀어보자.
위 문제에서 입력으로는 수식 하나가 주어지고 그 수식의 계산 결과를 출력하는 문제이다.
수식은 기본적으로 하나의 숫자(0 또는 1)가 주어지고, 이 숫자에 팩토리얼 또는 논리 반전 연산을 적용할 수 있다.
그러면 입력은 아래와 같이 주어진다.
0! -> 0 팩토리얼은 1
1! -> 1 팩토리얼은 1
!0 -> 0의 논리 반전은 1
!1 -> 1의 논리 반전은 0
!!0!! -> 0의 팩토리얼은 1 의 팩토리얼은 1. 1에 논리 반전을 두 번 적용하면 1
!!1!! -> 1의 팩토리얼은 1 의 팩토리얼은 1. 1에 논리 반전을 두 번 적용하면 1
팩토리얼이니 논리 반전이니 말이 어렵지만 간단히 정리하면
숫자 오른 쪽 부분에 ! 가 한 개라도 나오면 그 부분은 1로 평가
되고,
숫자 왼 쪽 부분에 ! 가 나오면 그 횟수만큼(짝/홀) 논리를 반전시킨다.
1!!!!! 이던 0!!!!!! 이던 1이라는 얘기다. 그러면 나머지는 숫자 앞에 있는 ! 연산만 남게 된다.
로직 구상
-
수식 맨 끝에 ! 가 붙어있으면 논리 반전 연산자를 적용하기 이전까지의 피연산자는 1이 된다.
그렇지 않으면 등장한 숫자가 피연산자가 된다.
-
숫자 앞에 있는 ! 갯수를 세어 짝수인지, 홀수인지에 따라 논리를 반전시킨다.
짝수: 피연산자 그대로
홀수: !피연산자
구현1
import sys
input = sys.stdin.readline
def eval(equation: str) -> int:
exclamation_occured = 0
if equation[-1] == '!': # 수식 뒤에 ! 가 붙어 있다면..
exclamation_occured = 1
operand = 0
reversal_count = 0
for ch in equation:
if ch.isdigit(): # 숫자 등장
if exclamation_occured: # 피연산자 1 로 간주
operand = 1
else:
operand = int(ch)
break
reversal_count += 1
if reversal_count % 2 == 0: # 숫자 앞 단에 붙어있는 느낌표 갯수가 짝수이면
return operand
else:
return int(not operand) # 홀수이면 논리 반전
def solution():
n = int(input())
for _ in range(n):
print(eval(input()[:-1]))
if __name__ == '__main__':
solution()
이 코드는 단순하지만 몇 가지 개선할 만한 부분이 있다.
-
exclamation_occured 라는 변수는 굳이 필요가 없다.
그냥 피연산자(operand) 라고 하자.
…그냥 조금 깔끔하게 써보자. 읽기 쉽고 이해하기 쉽게.
구현22
import sys
input = sys.stdin.readline
def eval(equation: str) -> int:
operand = int(equation[-1] == '!') # if 문은 불필요하다.
right = len(equation) - 1
while equation[right] == '!': # 숫자 찾기
right -= 1
operand = int(equation[right]) | operand # 느낌표가 있다(1)면 OR 연산으로 무조건 1처리
# if right < 0.. 하려다가 max 함수로 lower-bound 를 0으로 처리
reversal_count = max(right, 0)
# 같으면 0, 다르면 1. 논리 반전 횟수가 짝수(0)이면 그대로, 홀수(1)이면 반전
return operand ^ reversal_count % 2
def solution():
n = int(input())
for _ in range(n):
print(eval(input()[:-1]))
if __name__ == '__main__':
solution()
또 다르게도 풀어보았다.
구현333
import sys
input = sys.stdin.readline
def eval(equation: str) -> int:
for i, char in enumerate(equation):
if char in '01': # 숫자가 등장하면
n = int(char)
# 숫자를 기준으로 반갈
prefix = equation[:i]
suffix = equation[i+1:]
break
# 팩토리얼(!) 연산
if len(suffix):
n = 1 # 0!와 1! 모두 1이므로..
return n ^ (len(prefix) % 2) # 이거는 2번째 풀이와 동일하다.
def solution():
n = int(input())
for _ in range(n):
print(eval(input().rstrip('\n')))
if __name__ == '__main__':
solution()
마지막
오늘은 문제를 여러 가지 방법으로 풀어보았다.
난이도는 그렇게 어렵지는 않았지만 문제를 여러 방법으로 해결해보면서 로직 상 불필요한 부분을 없애고 코드가 간결해졌다.