[복습] Python 배우기 100~150

Leejaegun·2025년 10월 27일

코딩테스트 시리즈

목록 보기
47/49

1. 지능형 기차2

https://www.acmicpc.net/problem/2460

train = {}
for i in range(10):
    before, after = map(int,input().split())
    if i == 0:
        train[i] = after -before
    else:
        train[i] = train[i-1]-before+after

max_value = 0
max_name = ""
for k,v in train.items():
    if v > max_value:
        max_value = v
        max_name = k

print(train[max_name])
     

이 코드는 다음과 같이 고쳐쓸 수 있다.

train = {}
current = 0

for i in range(10):
    before, after = map(int, input().split())
    current = current - before + after
    train[i] = current  # i번째 역 도착 시 사람 수 기록

print(max(train.values()))

배운점

1) dict.get(key, default) 정확한 활용

  • 의도: 딕셔너리에서 key가 없을 때도 에러 없이 값을 읽거나, 부재 시 기본값으로 대체.

  • 형식: d.get(key, default)

    • key있으면: 그 값 반환
    • key없으면: default 반환(딕셔너리에는 추가되지 않음)

올바른 사용 패턴

  1. 카운팅/누적 집계
cnt = {}
for x in data:
    cnt[x] = cnt.get(x, 0) + 1
  1. 리스트에 안전하게 추가
bucket = {}
for k, v in pairs:
    bucket.setdefault(k, []).append(v)  # 또는 bucket[k] = bucket.get(k, []) + [v]
  1. 존재 여부에 따른 분기
threshold = scores.get("alice", 0)
if threshold >= 10:
    ...

잘못된 사용 예(이번 케이스)

# ❌ '계산된 값'을 저장해야 하는데, 그 값을 key로 '조회'해버림
train[i] = train.get(after - before, 0)
  • 여기서는 조회가 아니라 대입이 필요함. 즉, train[i] = after - before가 맞다.

2) 최댓값을 구하는 효율적·안전한 방법

값만 필요할 때(현재 코드 목적)

max_value = max(train.values())
print(max_value)

“최댓값의 키(역 번호)”도 필요할 때

  • 한 번에 키를 얻는 안전한 패턴:
max_key = max(train, key=train.get)  # 값이 최대인 키
print(train[max_key], max_key)
  • 동률(여러 개의 최대값) 처리:
best = [k for k, v in train.items() if v == max(train.values())]
# best에 동률 키 목록이 들어감

초기값·빈 딕셔너리 방어

if train:                      # 빈 딕셔너리 방어
    print(max(train.values()))
else:
    print(0)                   # 문제 요구사항에 맞는 기본값 선택

3) 자주 생기는 실수와 예방 팁

  • 콤마로 튜플 생성 실수:
    train[i] = expr, 0(expr, 0) 튜플이 되어 TypeError 유발. 반드시 콤마 제거.
  • 초기 참조 실수:
    train[i]를 채우기 전에 train[i]를 참조하지 말 것. 필요하면 current 같은 누적 변수를 사용.
  • get과 대입 혼동:
    조회(get)와 저장(대입 =)의 목적을 구분. 계산 결과를 키로 조회하지 말고 그대로 값에 대입.

요약 문장

  • .get조회 시 기본값 대체용이며 “계산값 저장”과는 무관하다.
  • 최댓값만 필요하면 max(d.values()), 키도 필요하면 max(d, key=d.get)을 쓰면 된다.
  • 이번 문제는 누적 변수 current로 갱신하고 필요 시만 딕셔너리에 기록하는 게 가장 깔끔하다.

다음 단계로는 “동률 처리”, “음수 입력 방어”, “입력 개수 가변화” 같은 요구가 생길 때 위 패턴을 그대로 확장하면 된다.

2. 숫자의 갯수

https://www.acmicpc.net/problem/2577

import sys
input = sys.stdin.readline
answer = {}
target = 1
for _ in range(3):
    num = int(input())
    target *= num

for i in str(target):
    answer[i] = answer.get(i,0) +1

for i in range(0,10):
    answer[str(i)] = answer.get(str(i),0)
    print(answer[str(i)])

이 소스코드는 다음과 같이 고쳐쓸 수 있다.

from collections import Counter

target = 1
for _ in range(3):
    target *= int(input())

count = Counter(str(target))  # 각 숫자 등장 횟수 세기

for i in range(10):
    print(count.get(str(i), 0))

배운점

(1) from collections import Counter를 잊지 말자 — 직접 딕셔너리 만들 필요 없다.
(2) num = int(input()) 대신 바로 target *= int(input())로 연산 단축 가능.
(3) cnt = Counter(str(target))로 각 숫자 빈도를 한 번에 구할 수 있다.
(4) cnt.get(str(i), 0)으로 없는 숫자도 0으로 안전하게 출력한다.

3.대표값

https://www.acmicpc.net/problem/2592

🧮 대표값(BOJ 2592) 풀이 정리

✅ 1. 기본 딕셔너리 풀이

nums = {}
total = 0
for _ in range(10):
    num = int(input())
    total += num
    nums[num] = nums.get(num, 0) + 1  # 등장 횟수 카운트

print(total // 10)                   # 평균
print(max(nums, key=nums.get))       # 최빈값

🧩 핵심 복습 포인트

  1. nums[num] = nums.get(num, 0) + 1

    • .get(key, default)는 key가 없으면 default값 반환.
    • 없을 때 0부터 시작해서 등장할 때마다 +1 → 카운팅 가능.
  2. 딕셔너리에서 key/value 접근법

    • value 최댓값: max(nums.values())
    • key 중에서 value가 가장 큰 것: max(nums, key=nums.get)

✅ 2. Counter를 이용한 간단한 풀이

from collections import Counter

nums = [int(input()) for _ in range(10)]

print(sum(nums) // len(nums))  # 평균

cnt = Counter(nums)
print(cnt.most_common(1)[0][0])  # 최빈값

🧠 Counter 동작 구조

  • Counter(nums) → 각 숫자의 빈도수를 자동으로 계산
    예: Counter({30: 4, 40: 3, 10: 2, 60: 1})
  • cnt.most_common(1) → 가장 자주 나온 값 1개 반환
    예: [(30, 4)]
  • cnt.most_common(1)[0][0](30, 4) 중에서 30만 추출

📘 요약 비교

방식코드 길이가독성원리
dictionary길지만 원리 이해에 도움★★★★☆.get()으로 직접 count
Counter짧고 직관적★★★★★자동 카운트 및 most_common() 제공

4. 이진수

https://www.acmicpc.net/problem/3460

T = int(input())
for _ in range(T):
    n = int(input())
    bin_n = str(bin(n)[2:])
    bin_n = bin_n[::-1]
    indices = [i for i,x in enumerate(bin_n) if x == "1"]
    print(" ".join(str(i) for i in indices))

🧩 배운 점 정리

(1) 진법 변환

변환방법예시설명
10진수 → 2진수bin(n)[2:]bin(13) → '0b1101''1101'앞의 '0b'는 접두사이므로 잘라냄
10진수 → 8진수oct(n)[2:]oct(13) → '0o15''15''0o' 접두사 제거
10진수 → 16진수hex(n)[2:]hex(13) → '0xd''d''0x' 접두사 제거
n진수 → 10진수int(string, base)int('1101', 2) → 13문자열을 주고 진법을 지정
직접 정의한 n진수 변환재귀나 반복문으로 구현 가능6진수, 12진수 등기본 내장 함수에는 없음

💡 chr(n)은 숫자를 문자 코드(ASCII) 로 바꾸는 함수이므로
진법 변환용이 아니라 문자 변환용이다.
예: chr(65)'A', ord('A')65

(2) .join()의 원리

  • 문법: "구분자".join(iterable)

  • 조건

    • iterable은 반복 가능한 객체(list, tuple 등)
    • 내부 원소는 모두 문자열(str) 이어야 한다.
예시결과설명
" ".join(['1', '2', '3'])'1 2 3'정상
"".join(['a', 'b', 'c'])'abc'구분자 없음
" ".join([1, 2, 3])TypeError원소가 int
" ".join(str(i) for i in [1,2,3])'1 2 3'문자열로 변환 후 정상

📘 요약

  1. 진법 변환 핵심

    • bin(), oct(), hex() → 문자열 접두사 제거
    • 반대로는 int(string, base)
    • chr()는 진법 변환이 아니라 문자 코드 변환 함수
  2. .join() 핵심

    • 문자열만 합칠 수 있다.
    • iterable 하나만 인자로 받는다.
    • 숫자 리스트는 map(str, iterable) 또는 컴프리헨션으로 문자열화 필요.

진수변환 custom 코드

def to_base(n:int, base:int) -> str:
	if not (2 <= base <= 36):
    	raise ValueError("base 는 2~36이하만 지원")
    if n == 0:
    	return "0"
    digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"  # 최대 36진수까지 지원
    result = []

    is_negative = n < 0
    n = abs(n)
    
    while n > 0:
    	remainder = n % base
        result.append(digits[remainder])
        n //= base
   
    if is_negative:
    	result.append("-") #음수용
    return ''.join(reversed(result))

-> 몫은 밑으로 나머지는 digits으로 처리해서 result 에 더하고 마지막에 reversed()로 처리.

반대로 진법변화(n -> 10)

https://www.acmicpc.net/problem/2745

N,B = input().split()
B = int(B)

print(int(N,B))

파이썬은 내장함수가 있기 때문에 자동으로 해준다!
즉,to_base()는 10진수 → B진수 변환용
int(N, B)는 B진수 → 10진수 변환용
하지만custom으로 짜보면?

N, B = input().split()
B = int(B)

digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = 0

for i, ch in enumerate(reversed(N)):   # 뒤에서부터 자리수 계산
    value = digits.index(ch)           # 해당 문자의 숫자값
    result += value * (B ** i)

print(result)

5. 쉽게푸는문제

https://www.acmicpc.net/problem/1292

A,B = map(int,input().split())
seq = []
for i in range(1,1001):
    seq += [i] * i

print(sum(seq[A-1:B]))    

💡 배운점 정리

문제:
1을 한 번, 2를 두 번, 3을 세 번, … 이런 식으로 수열 1, 2, 2, 3, 3, 3, …을 만들어
A번째부터 B번째까지의 합을 구하는 문제.


초기 시도:

ans = []
for i in range(1, 10):
    ans.append([i] * i)

이렇게 하면 ans = [[1], [2,2], [3,3,3], …] 처럼 리스트 안에 리스트가 생긴다.
이유는 append()리스트 전체를 하나의 요소로 추가하기 때문이다.


해결 방법:
+= 연산을 사용하면, 리스트 안에 리스트가 아니라 리스트를 펼쳐서 붙이기(extend) 가 된다.

seq = []
for i in range(1, 10):
    seq += [i] * i

이렇게 하면
seq = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, …]
처럼 원하는 형태의 수열이 만들어진다.

최종 코드:

A, B = map(int, input().split())
seq = []
for i in range(1, 1001):
    seq += [i] * i
print(sum(seq[A-1:B]))

핵심 포인트:

  • append() → 리스트를 요소로 추가 (중첩 구조 생성)
  • += 또는 extend() → 리스트를 병합(펼쳐서 추가)

이 차이만 정확히 이해하면 유사한 문제에서도 헷갈리지 않는다.

6. 약수

https://www.acmicpc.net/problem/1037


n = int(input())
real =  list(map(int,input().split()))
print(max(real) * min(real))

배운점
약수의 성질을 살펴보자.24를 예로 들면 (2,12),(3,8),(4,6)으로 조합된다
조합된거에서 각 곱하면 된다
즉, NN = NminN_{min} x NmaxN_{max} 하면 된다.

7. 동전0

https://www.acmicpc.net/problem/11047

N,K = map(int, input().split())
coins = [int(input()) for _ in range(N)]
count = 0

for coin in reversed(coins):
    if K >= coin:
        count += K //coin
        K %= coin
print(count)

배운점

✅ 배운 점 정리 (보완 버전)

  1. 탐욕법(Greedy)의 핵심 사고방식
    → "가장 큰 단위부터 가능한 한 많이 써라."
    동전이 항상 “작은 단위의 배수 관계”라면,
    이 방법이 항상 최적해를 보장한다.

  2. reversed(coins)의 의미
    입력은 오름차순(1, 5, 10, 50, …)으로 들어오므로
    reversed()로 뒤집어 큰 단위부터 순회한다.

  3. if K >= coin: 조건의 역할
    너무 큰 단위는 자연스럽게 무시된다.
    즉, 4790원일 때 5000원 동전은 패스하고,
    1000원 단위부터 계산이 시작된다.

  4. K // coinK %= coin의 관계

    • K // coin: 지금 동전을 몇 개 쓸 수 있는가
    • K %= coin: 그만큼 사용 후 남은 금액
      이 둘로 매 단계마다 잔액을 줄여가며 총 동전 수를 누적한다.
  5. 결국 작은 동전까지 갈 필요가 없다
    위의 과정이 “큰 단위에서 충분히 나눠지면 끝나기 때문”.
    이게 바로 탐욕법이 잘 작동하는 이유다.


🔹 핵심 한 줄 요약

"큰 단위부터 순서대로, 가능한 만큼 쓰고 남은 금액만 다음 단위에 넘긴다."

8. 일곱난쟁이

https://www.acmicpc.net/problem/2309

from itertools import combinations
dwarfs = [int(input()) for _ in range(9)]
combs = combinations(dwarfs,7)

for comb in combs:
    if sum(comb) == 100:
        for i in sorted(comb):
            print(i)
        break
        

배운점

✅ 배운 점 (정리 버전)

  1. itertools.combinations() 출력 확인

    • combinations()iterator(이터레이터) 형태라서,
      print(combs) 하면 주소처럼 object at 0x... 만 나옵니다.

    • 내부 내용을 보려면 list()로 감싸야 실제 조합을 확인할 수 있습니다.
      예:

      print(list(combinations([1,2,3], 2)))
      # [(1, 2), (1, 3), (2, 3)]
  2. 정답 조합을 찾으면 즉시 종료 (break)

    • 문제 조건상 정답은 유일하므로,
      찾은 뒤에도 루프를 계속 돌면 불필요한 탐색과 중복 출력이 생길 수 있습니다.
    • 따라서 조건이 맞는 조합을 찾으면 즉시 break로 루프를 종료해야 합니다.
  3. 출력은 오름차순 정렬 필요

    • 문제에서 난쟁이의 키를 오름차순으로 출력하라고 했기 때문에
      sorted(comb)를 통해 순서를 맞춰 출력해야 합니다.

🔹 추가 팁

  • combinations조합이 메모리에 한꺼번에 만들어지지 않고
    하나씩 생성되므로, 메모리 효율도 좋습니다.
    (그래서 list()는 디버깅할 때만 쓰는 게 좋습니다.)
  • 이 문제는 “9명 중 7명을 뽑는 경우의 수” → C(9,7) = 36
    즉, 브루트포스로 다 검사해도 충분히 빠르게 풀립니다.

요약하자면,

“조합은 list()로 확인하고, 정답은 찾자마자 멈추자.”
이 두 개가 핵심 포인트입니다.

8. 짝수를 찾아라

https://www.acmicpc.net/problem/3058

T = int(input())

for _ in range(T):
    ans = []
    nums = list(map(int, input().split()))
    for num in nums:
        if num % 2 ==0:
            ans.append(num)
    print(f"{sum(ans)} {min(ans)}")    

배운점

💡 핵심 정리

  1. 입력 형태를 먼저 확인해야 한다.

    • 만약 숫자들이 한 줄에 "1 2 3 4 5 6 7" 처럼 공백으로 구분되어 들어온다면,
      list(map(int, input().split())) 로 한 번에 읽어야 한다.
    • 반면, 숫자가 여러 줄로 들어온다면
      [int(input()) for _ in range(7)] 으로 읽는다.
  2. 이 문제는 한 줄에 여러 숫자가 입력되는 케이스이므로
    nums = list(map(int, input().split())) 가 맞는 방법이다.

  3. ans 리스트에는 짝수만 필터링해서 저장하고,
    sum(ans)min(ans)를 각각 출력하면 된다.

✅ 한 문장 요약

입력이 공백으로 구분된 한 줄이라면 input().split()으로 처리해야 하며,
이 문제는 그 형태이므로 list(map(int, input().split()))가 올바른 입력 방식이다.

9. 오늘의 날짜는?

https://www.acmicpc.net/problem/16170

from datetime import datetime, timezone, timedelta

uk = datetime.now(timezone(timedelta(hours = 0)))
print(uk.year, uk.month,uk.day)

배운점
(1) 현재시간을 나타날때는 위 from datetime import datetime, timezone, timedelta를 기억하자

그리고 쓰는 방법 또한
datetime.now(timezone(timedelta(hours=0)))으로 기억하도록 하자.
그러면 이러한 문제는 개꿀~

10. 열개씩끊어서

https://www.acmicpc.net/problem/11721

s = input().strip()
for i in range(0,len(s),10):
    print(s[i:i+10])

🔹 배운 점

  1. 문자열을 10글자씩 잘라 출력할 때 range(0, len(s), 10) 구문을 사용하면 인덱스 계산을 직접 하지 않아도 된다.
    → 시작값(0), 끝값(len(s)), 간격(10)을 지정하면 자동으로 0, 10, 20, … 형태로 반복된다.
  2. 처음엔 quotient, remainder = divmod(len(s), 10)처럼 나눗셈으로 범위를 계산하려고 했는데, 이런 복잡한 계산은 필요 없었다.
  3. 슬라이싱(s[i:i+10])은 끝 인덱스가 문자열 길이를 넘어가더라도 오류 없이 잘려서 반환되므로 안전하다.
  4. 결국 간단한 브론즈 문제라도, 기본기를 다시 다지는 데 큰 도움이 된다 — “직관적인 접근이 항상 더 낫다.”

요약:
“문제를 복잡하게 만들지 말자. 단순한 구조가 가장 강력하다.”

11. 팩토리얼 0의 갯수

https://www.acmicpc.net/problem/1676

def factorial(n:int) -> int:
    ans = 1
    if n == 0:
        return 1
    for i in range(1,n+1):
        ans *= i
    return ans

import sys
input = sys.stdin.readline
N = int(input())
_N =  str(factorial(N))

count = 0
for i in reversed(_N):
    if i == "0":
        count += 1
    else:
        break

print(count)        

배운점
(1) 팩토리얼을 너무 간단하게 정의했다. O(N)의 시간복잡도를 가진다. 뭐 dp로 풀어도 같겠지만.

# dp 로 풀었을때
def factorial(n:int) -> int:
	df = [1] * (n+1)
    for i in range(1 ,n+1):
    	dp[i] = dp[i-1] * i
    return dp[n]

뭔가 좀더 있어 보인다.

(2) 이렇게 하는것보다 좀 더 효율적인 방식이 있다고 한다. from gpt

import sys
input = sys.stdin.readline

N = int(input())
count = 0

while N >= 5:
    count += N // 5
    N //= 5

print(count)

이 코드는 “N! (팩토리얼)의 끝자리 0 개수를 효율적으로 세는 방법”입니다.
하나씩 천천히 풀어볼게요.


1️⃣ 끝자리 0이 생기는 이유

0은 2 × 5로 만들어집니다.
예를 들어:

10! = 1×2×3×4×5×6×7×8×9×10

여기서 2는 여러 번 등장하지만, 5는 상대적으로 적습니다.
따라서 0의 개수는 5가 몇 번 등장하느냐에 달려 있습니다.

즉,

끝자리 0의 개수 = 1부터 N까지 수에 포함된 5의 개수

2️⃣ 예시: N = 10일 때

1부터 10까지 곱할 때, 5의 배수는 다음과 같습니다:

5, 10

각각 5를 한 번씩 포함하죠.
→ 총 2번 등장 → 끝자리 0은 2개.


3️⃣ 그런데 N이 더 클 때 (예: N=25)

5, 10, 15, 20, 25

이 중 25는 5×5, 즉 5를 두 번 포함합니다.
따라서 단순히 “5의 배수 개수”만 세면 안 되고,
“5가 몇 번 곱해졌는지”까지 고려해야 합니다.

그래서 한 번 5로 나누는 것으로는 부족합니다.


4️⃣ 코드의 의미 단계별 해석

while N >= 5:
    count += N // 5
    N //= 5
단계NN // 5 의미누적 count설명
110020205의 배수 개수 (5, 10, …, 100)
22042425, 50, 75, 100에 있는 추가 5
340245보다 작으므로 종료

👉 결과적으로 24개의 5가 존재, 즉 0이 24개.

5️⃣ 한 줄로 요약

  • N // 5 → 5의 배수에서 생기는 5의 개수
  • N //= 5 → 다음 루프에서 25, 125 등 “5가 여러 번 곱해진 수”까지 카운트
  • 반복 종료 시 count = N!의 끝자리 0 개수

6️⃣ 예시로 검증

N실제 N! 끝의 0 개수계산 결과
511
1022
2566
1002424

뭐 그렇다고 한다 .. 신기하네??
이렇게 푸는 사람이있을려나?? 나는 접근조차도 못하겠는데

12. ROT13

https://www.acmicpc.net/problem/11655

def ROT13(s:str) -> str:
    result = []
    for ch in s:
        if "A" <= ch <= "Z":
            result.append(chr((ord(ch) - ord("A") + 13) % 26 + ord("A"))) 
        elif "a" <= ch <= "z":
            result.append(chr((ord(ch) - ord("a") + 13) % 26 + ord("a"))) 
        else:
            result.append(ch)
    return "".join(result)
import sys
input = sys.stdin.readline
s  = input().rstrip()
print(ROT13(s))

배운점

🧠 배운 점 정리

  1. ord()chr()의 개념 이해

    • ord() → 문자(character)를 유니코드(정수) 로 변환. (“ordinal” = 순서 번호)
    • chr() → 정수(유니코드)를 문자(character) 로 변환.
    • chr(ord('A')) == 'A' 형태로 서로 역함수 관계를 가진다.
  2. 문자 범위를 문자열로 비교할 수 있음

    • 'A' <= ch <= 'Z'
    • 'a' <= ch <= 'z'
      문자열끼리도 사전식(lexicographical) 비교가 가능하다는 사실을 배움.
  3. ROT13 변환 과정의 논리적 구조

    • (1) ord(ch) - ord('A') → ‘A’를 기준으로 정규화 (0~25)
    • (2) +13 → ROT13 규칙에 따라 13칸 회전 이동
    • (3) %26A~Z 범위에서 순환 회전
    • (4) +ord('A') → 다시 문자 코드로 복원(복호화)
    • 결국, "정규화 → 이동 → 순환 → 복호화" 흐름으로 구성됨.
  4. 출력 형식 오류 해결

    • input().rstrip()을 사용하여 입력 문자열 끝의 개행 문자(\n) 를 제거.
    • 문제에서 요구하는 출력 형식을 정확히 맞추기 위해 필수적인 처리임.

🧩 요약

이 문제를 통해

  • 문자와 숫자 간 변환(ord, chr)
  • 아스키/유니코드 범위 제어
  • 순환 연산(%)
  • 문자열 비교와 입력 처리(rstrip)

등의 개념을 실습하며 문자열 암호화 로직의 기본 구조를 체계적으로 이해할 수 있었다.

추가로 다른 사람의 코드가 있는데 이것 또한 간단해서 좋았다.

import sys
for x in sys.stdin.readline().rstrip():
    if x.isalpha():
        c = 97 if x.islower() else 65
        print(chr(c + (ord(x) + 13 - c) % 26), end='')
    else: print(x, end='')

13. 알파벳거리

https://www.acmicpc.net/problem/5218

T = int(input())
import sys
input = sys.stdin.readline
for _ in range(T):
    s1 ,s2 = map(str, input().split())
    distances = []
    for i in range(len(s1)):
        diff = ord(s2[i])- ord(s1[i])
        if diff < 0:
            diff += 26
        distances.append(diff)
    print("Distances:", *distances)

배운점

💡 배운 점 요약

  1. 리스트 초기화 위치

    • distancesfor i in range(len(s1)): 안에 두면 매 반복마다 초기화되어 값이 누적되지 않는다.
    • 따라서 문자 전체를 순회하기 전에 한 번만 초기화해야 한다.
  2. 문자 거리 계산 순서

    • ord(s2[i]) - ord(s1[i])
      → 기준은 첫 번째 문자열에서 두 번째 문자열로의 거리를 계산하는 것이다.
      → 음수가 나오면 알파벳이 한 바퀴 돌아간 것으로 간주해 +26을 더한다.
  3. 출력 형식

    • print("Distances:", *distances)
      *를 사용하면 리스트의 각 요소를 공백으로 구분해 출력할 수 있다.
      → 예: [1, 3, 5]1 3 5

🧠 핵심 개념 정리

  • ord() : 문자를 아스키코드(숫자)로 변환
  • chr() : 숫자를 문자로 변환
  • 알파벳은 26개 → 음수 결과에 +26 보정
  • 리스트 언패킹(*list)을 활용하면 출력이 간결해짐

14. !밀비 급일

https://www.acmicpc.net/problem/11365

while True:
    _ls = list(input().split())
    ans = []
    if _ls[0] == "END":
        break
    for i in reversed(_ls):
        ans.append(i[::-1])
    print(" ".join(str(i) for i in ans))

배운점
(1) _ls =="END" 하면 무조건 False가 나옴 왜냐하면 _ls는 기존에 리스트로 정의했으니까.
따라서 _ls[0] 이라고 해줘야함. 이거는 사소하지만 나중에 안됨 ㅋㅋ

(2) 더 깔끔하게 쓰는 방법도 있음

while True:
    line = input()
    if line == "END":
        break
    print(" ".join(word[::-1] for word in line.split()[::-1]))

위 방법은 한줄로 print(" ".join(word[::-1] for word in line.split()[::-1])) 로 고쳤음.

15. 문자열 분석

https://www.acmicpc.net/problem/10820

import sys

for line in sys.stdin:
    line = line.strip("\n")
    low = upp = nums = space = 0
    
    for c in line:
        if c.islower():
            low += 1
        elif c.isupper():
            upp += 1
        elif c.isnumeric():
            nums += 1
        else:
            space += 1
    print(low,upp,nums,space)

📘 배운 점 정리

(1) 입력 개수 N을 모를 때 — sys.stdin 활용

  • 문제에서 입력 줄 수가 정해지지 않았고 종료 신호(END 등)도 없음.
  • while문으로 처리하기 어렵기 때문에 for line in sys.stdin: 형태로 EOF까지 자동 읽기.
  • 각 줄의 개행문자를 제거하기 위해 line.strip("\n") 사용.

✅ 핵심 원리
sys.stdin은 파일처럼 동작하며,
입력이 끝날 때까지(EOF) 한 줄씩 자동으로 반복된다.


(2) is 계열 메서드의 활용

문자열 판별 메서드는 코딩테스트에서 자주 쓰인다.
아래는 대표적인 것들이다.

메서드참(True) 조건예시
isalpha()모든 문자가 알파벳(a–z, A–Z) 일 때"abc".isalpha() → ✅ True
"abc1".isalpha() → ❌ False
isdigit()모든 문자가 0–9 숫자일 때"123".isdigit()" → ✅
"12a".isdigit() → ❌
isnumeric()모든 문자가 숫자(0–9 + 유니코드 숫자 포함, 예: Ⅻ)일 때"Ⅻ".isnumeric() → ✅
isalnum()모든 문자가 알파벳 또는 숫자일 때"abc123".isalnum() → ✅
islower()모든 문자가 소문자일 때 (한 글자 이상)"abc".islower()" → ✅
"Abc".islower()" → ❌
isupper()모든 문자가 대문자일 때"ABC".isupper()" → ✅
"ABc".isupper()" → ❌
isspace()모든 문자가 공백 문자(스페이스, 탭, 줄바꿈 등) 일 때" ".isspace()" → ✅
istitle()문자열이 Title Case (단어 첫 글자만 대문자)일 때"Hello World".istitle()" → ✅
"Hello world".istitle()" → ❌
isprintable()모든 문자가 출력 가능한 문자(제어문자 제외) 일 때"abc!".isprintable()" → ✅
isascii()모든 문자가 ASCII(0~127) 범위일 때"abc".isascii()" → ✅
"한글".isascii()" → ❌

🧠 추가 팁

  • isdigit()isnumeric()은 비슷하지만, 후자는 로마 숫자, 분수, 동아시아 숫자 등 유니코드 숫자도 True로 인식.
  • isalpha()는 오직 알파벳만 허용하며, 공백이나 숫자가 섞이면 False.
  • 문자열 판별 메서드는 모두 빈 문자열에는 False를 반환한다.

추가 문제

https://www.acmicpc.net/problem/10951
이 문제도 똑같이 EOF가 없는 상황

import sys

for line in sys.stdin:
    line = line.strip("\n")
    A,B = line.split()
    print(int(A)+int(B))
profile
Lee_AA

0개의 댓글