99클럽 코테 스터디 3일차 TIL [04/02]

[시작]

참여 기간 : 2025/03/31 ~ 2025/04/28

참여 난이도 : 파이썬 / 비기너

⏳ 코테 스터디 진행도 🧱 : [▰▰▰▰▰░                                             ] 3/29일 (10%)

본 글에서 다룬 문제 : 백준 31458번

문제 푸는 데 걸린 시간 : 28분

 

 

 

[오늘의 문제]

오늘의 문제는 백준 31458번

예상대로 초콜릿이랑 아무 상관없었다 ㅎㅎ;

 

 

[문제 분석]

수식의 개수 T가 주어짐

T개의 수식이 한줄에 하나씩 입력

하나의 수식은 a개의 느낌표, 정수 n, b개의 느낌표가 공백 없이 순서대로 합쳐진 형태

물론 정수n은 0 혹은 1 임

n! 은 팩토리얼인데 0! 1! 둘 다 결과가 1 임

!n은 논리 반전이여서 !0 =1, !1=0이라 보면 됨

팩토리얼이나 논리 반전이 중첩되어 있으면 중첩된 횟수만큼 계산

대신 우선순위는 팩토리얼이 먼저

 

 

[의사 코드]

  1. 입력
    1. 수식의 개수 T 입력
    2. T개의 수식을 하나씩 입력
  2. 느낌표 개수 계산
    1. 문자열 왼쪽 느낌표 개수 a
    2. 문자열 오른쪽 느낌표 개수 b
  3. 숫자 부분
    1. 전제 수식에서 느낌표 a와 b만큼을 제외한 부분이 숫자
    2. 오른쪽 느낌표가 있을 경우와 없을 경우를 구분하여 숫자 추출해야 함
  4. 정수 변환
    1. 추출한 숫자 문자열을 정수로 변환
  5. 팩토리얼 적용
    1. 오른쪽 느낌표가 하나 이상 있으면 팩토리얼 연산 적용
    2. 결과는 1로 동일
  6. 논리 반전 적용
    1. 왼쪽 느낌표의 개수만큼 반복해서 현재 값을 논리 반전
  7. 출력
    1. 최종적으로 계산된 값을 출력

 

 

[의사 코드를 실제 코드로 구현]

import sys
import math

T = int(sys.stdin.readline().strip())
for _ in range(T):
    expr = sys.stdin.readline().strip()
    a = len(expr) - len(expr.lstrip('!'))
    b = len(expr) - len(expr.rstrip('!'))
    if b > 0:
        number_str = expr[a:-b]
    else:
        number_str = expr[a:]
    n = int(number_str)
    if b > 0:
        n = math.factorial(n)
    for _ in range(a):
        n = 1 if n == 0 else 0
    print(n)

★ 코드 설명 ★

  • math 모듈
    • 팩토리얼 계산을 위해 사용
    • math.factorial
  • for문
    • T개의 수식을 처리하기 위해 사용
  • expr = sys.stdin.readline().strip()
    • 각 수식을 한 줄씩 읽어옴
    • 수식이어서 expr로 변수명 적음
  • a = len(expr) - len(expr.lstrip('!'))
    • expr.lstrip('!')는 문자열의 왼쪽에서 모든 느낌표를 제거한 문자열을 반환
      • 어제 TIL에서 메서드 정리할 때 다뤘음(여기서 써먹네)
    • 원래 문자열 길이 - 왼쪽 모든 느낌표 제거한 문자열 길이
      • 왼쪽에 몇 개의 느낌표가 있는지 알 수 있음
    • a는 즉 왼쪽에 있는 느낌표 개수이고 나중에 논리 반전 연산에서 사용할 거임
  • b = len(expr) - len(expr.rstrip('!'))
    • expr.rstrip('!')는 문자열의 오른쪽에서 모든 느낌표를 제거한 문자열을 반환
    • 원래 문자열 길이 - 오른쪽 모든 느낌표 제거한 문자열 길이
      • 오른쪽에 몇 개의 느낌표가 있는지 알 수 있음
    • b는 오른쪽에 있는 느낌표 개수이고 팩토리얼 연산을 적용할 횟수 결정
  • 숫자 부분 추출
    • 수식은 왼쪽과 오른쪽에 느낌표로 둘러싸인 구조
    • if b > 0:
      • 오른쪽에 느낌표가 있다면, 숫자 부분은 왼쪽 a개의 느낌표를 제외하고 뒤쪽 b개의 느낌표를 제외한 부분
      • number_str = expr[a:-b]
    • else:
      • 오른쪽에 느낌표가 없으면 숫자 부분은 왼쪽의 느낌표만 제외한 뒤 나머지 전부
      • expr[a:]
  • n = int(number_str)
    • 추출한 숫자를 정수로 변환
  • 팩토리얼 처리
    • if b > 0: 에서 오른쪽에 느낌표가 하나 이상 있다면 팩토리얼 연산 적용
    • n = math.factorial(n) 로 계산하는데 결과는 1로 고정이긴 함
    • 사실 팩토리얼 함수 안 써도 푸는데 문제가 없다! 근데 다른 문제에서는 써야 할 수도 있으니 써봤음
  • 논리 반전
    • for _ in range(a):를 사용해서 왼쪽 느낌표의 개수만큼 논리 반전 연산 수행
    • n = 1 if n == 0 else 0
  • 최종 결과 출력 print(n)

 

 

 

 

 

[제출 결과]

 

 

 

[실수한 부분]

vs code에서 CPH Judge로 돌려보고 맞으면 제출

저 코드가 나오기 전에 4번 정도 오답이었다.

  1. 한 줄만 처리하는 코드로 작성해서 오답 (여러 줄 입력인데)
  2. 문자열 슬라이싱으로 수정하는데 인덱스가 꼬였음
  3. 수식의 구조를 제대로 분리 못함 (단순 문자 단위로 처리하려 했음ㅠ)
  4. 마지막엔 출력을 잘못함 ㅎㅎ;

원래 코드는 중첩 반복문을 사용했고 for문 while문 골고루 썼다.

근데 가독성이 너무 안 좋아서 지우고 다시 작성했음

 

 

 

[다른 코드]

백준에서 다른 분이 제출한 코드를 가져와봤다.

import sys
input = sys.stdin.readline

for _ in range(int(input())):
    s = input().strip()

    num = '0' if '0' in s else '1'

    # parts = s.split(num) #숫자 기준으로 리스트로 나누기 ['!!', '!!']
    left_n = s.split(num)[0].count('!')
    right_n = s.split(num)[1].count('!')

    if right_n > 0:
        num = '1'
    if left_n % 2 == 1:
        num = '0' if num == '1' else '1'

    print(num)
        


# 만약 오른쪽에 !이게 있으면 무조건 1로 바꾸기
# 그 다음 왼쪽에 !가 홀수면 반전(0->1, 1->0) 짝수면 그대로

내 코드와 뭐가 다른지 살펴보면

  • 문자열 분리 방식이 다름
    • 나 : 앞뒤 느낌표 개수를 lstrip(), rstip()을 사용해 계산하고 슬라이싱으로 숫자 부분 추출
    • 이 코드 : split(num)을 사용해서 숫자를 기준으로 왼쪽 오른쪽 느낌표를 한 번에 분리한 뒤 count('!')로 개수 확인
  • 팩토리얼 연산 부분이 다름
    • 나 : 팩토리얼 함수를 이용
    • 이 코드 : 오른쪽에 느낌표가 있으면 바로 num을 '1'로 만들었음

 

 

 

[마무리]

어렵다 어려워... 파이썬 문법 부분 지식이 부족하다 느낀다.

수학 공식 모르는데 문제 어찌어찌 풀어보려 하는 느낌