선풍기 대수를 구하는 디버깅 문제. 교실마다 선풍기 4대가 있고, 선풍기 1대당 k명에게 바람을 보낼 때, 추가로 필요한 선풍기 총 대수를 구하는 코드에서 한 줄 수정.
break → continuefor s in student:
s -= 4 * k
if s <= 0:
break # ❌ 루프 전체 종료 — 뒤 교실 무시
continue # ✅ 이 교실 건너뛰고 다음으로
answer += (s + k - 1) // k
| 키워드 | 동작 |
|---|---|
break | 루프 전체 종료 |
continue | 이번 반복 건너뛰고 다음 반복으로 |
pass | 아무것도 안 함 (다음 줄 실행) |
이 문제에서 pass를 쓰면 if 블록 이후의 answer += ... 줄이 실행되어 0이하 값이 더해질 수 있다. continue가 정확한 답이다.
팝업스토어를 열 최적의 날짜를 찾는 문제. n일간의 매출액 중 연속 k일의 합이 최대인 값을 구한다.
연속 k개 합을 구할 때, 매번 sum()을 쓰면 느리다. 대신 "하나 빼고 하나 더하기"로 O(n)에 해결한다.
# 첫 윈도우 합
rsum = sum(revenue[0:k])
answer = rsum
# 윈도우를 한 칸씩 밀기
for i in range(k, len(revenue)): # ← i는 k부터!
rsum = rsum - revenue[i - k] + revenue[i]
if answer < rsum:
answer = rsum
핵심 포인트:
i는 항상 윈도우의 오른쪽 끝을 가리킴revenue[i-k]는 빠지는 왼쪽 값, revenue[i]는 새로 들어오는 오른쪽 값예시 (k=4, [1, 1, 9, 3, 7, 6, 5, 10]):
첫 윈도우: [1, 1, 9, 3] → sum = 14
i=4: 1 [1, 9, 3, 7] → 14 - 1 + 7 = 20
i=5: [9, 3, 7, 6] → 20 - 1 + 6 = 25
i=6: [3, 7, 6, 5] → 25 - 9 + 5 = 21
i=7: [7, 6, 5, 10] → 21 - 3 + 10 = 28 ← 최대!
수업 중 질문: "range 시작값으로 0이나 1이 아닌 k를 쓰는 이유?"
→ i가 len을 넘지 않으면서도 i-k가 0부터 시작하게 하려는 것. i가 윈도우의 오른쪽 끝이기 때문에, i=k일 때 첫 번째로 빠지는 값이 revenue[0]이 된다.
미용실(HairShop)과 레스토랑(Restaurant)이 Shop을 상속받아 각각 예약 조건을 다르게 구현하는 문제. 빈칸 8개를 채워야 한다.
class HairShop(Shop): # 상속
def __init__(self):
super().__init__()
def reserve(self, customer): # 메서드 오버라이드
if customer.num_of_people != 1: # 1명 아니면 거절
return False
for r in self.reserve_list:
if r.time == customer.time: # 시간 겹침 체크
return False
self.reserve_list.append(customer)
return True
class Restaurant(Shop):
def reserve(self, customer):
if customer.num_of_people < 2 or customer.num_of_people > 8:
return False
count = 0
for r in self.reserve_list:
if r.time == customer.time:
count += 1
if count >= 2: # for문 밖에서 판단!
return False
self.reserve_list.append(customer)
return True
포인트: Restaurant의 count >= 2 체크는 for문 밖에서 한다. 안에서 하면 아직 다 세지도 않았는데 판단하게 될 수 있다.
이 문제는 10차 세션에서 배운 클래스 상속 개념으로 8개 빈칸 전부 1차 정답!
두 문자열 s1, s2를 이어붙이되, 한쪽 끝과 다른 쪽 시작이 겹치면 한 번만 쓴다. s1+s2, s2+s1 중 더 짧은 길이를 return.
def solution(s1, s2):
answer = 0
std_len = min(len(s1), len(s2))
dup_len = 0
for i in range(1, std_len + 1): # ← +1 주의!
# s2 뒤에 s1 붙이는 경우 (s1 시작 = s2 끝)
if s1[:i] == s2[-i:]:
dup_len = i
# s1 뒤에 s2 붙이는 경우 (s1 끝 = s2 시작)
if s1[-i:] == s2[:i] and i > dup_len:
dup_len = i
answer = len(s1) + len(s2) - dup_len
return answer
주의: range(1, std_len)이 아니라 range(1, std_len + 1) — 겹침이 짧은 쪽 문자열 전체 길이와 같을 수 있기 때문이다.
화면에 14자를 표시하는 전광판에서, 문구가 왼쪽으로 1초에 한 칸씩 스크롤된다. 주어진 초(second)에 화면에 보이는 문자열을 return.
def solution(phrases, second):
answer = ''
text = phrases.zfill(len(phrases) * 2).replace("0", "_")
d_text = text * 2
cal_sc = second % len(text)
answer = d_text[cal_sc:len(phrases) + cal_sc]
return answer
단계별 동작:
1. zfill(28): "happy-birthday" → "00000000000000happy-birthday" (14개의 0 + 문구)
2. .replace("0", "_"): "______________happy-birthday" (밑줄 14개 + 문구)
3. text * 2: 문자열을 두 번 이어붙여서 순환 처리
4. second % len(text): 나머지 연산으로 반복 주기 처리
5. 슬라이싱으로 14글자 추출
수업 중 질문: "왜 text를 두 번 붙이나요?"
→ 슬라이싱이 문자열 끝을 넘어가면 잘린다. 예를 들어 t=20일 때text[20:34]인데 text는 28자라 8글자만 나온다. text*2로 56자를 만들어두면 어디서 잘라도 항상 14글자가 보장된다.
주의: str은 Python 내장함수이므로 변수명으로 사용하면 안 된다! text, display_str 같은 이름을 쓰자.
문제 4에서 s1[-i:] 같은 표현이 나왔는데, 왜 이게 "뒤에서 i글자"가 되는지 정리.
s = "hello"
# h e l l o
# 양수: 0 1 2 3 4
# 음수:-5 -4 -3 -2 -1
s[-1:]은 사실 s[-1:len(s)]와 같다. 뒤쪽을 생략하면 끝까지라는 뜻.
s[-1:] # s[-1:5] → "o" (뒤 1글자)
s[-2:] # s[-2:5] → "lo" (뒤 2글자)
s[-3:] # s[-3:5] → "llo" (뒤 3글자)
마찬가지로 s[:3]은 s[0:3]과 같다. 앞쪽 생략하면 처음부터.
수업 중 질문: "음수 인덱스를 쓰면 거꾸로 출력되나요?"
→ 아니다! 음수는 시작 위치만 뒤쪽일 뿐, 출력 순서는 왼→오 그대로다.
s = "hello"
s[-3:] # "llo" ← 뒤에서 3글자를 순서대로
s[::-1] # "olleh" ← 이게 진짜 역순! (step이 -1)
역순은 step에 -1을 줘야 한다. 음수가 나오는 위치가 다르다:
# 뒤 3글자를 거꾸로 출력하려면?
s[:-4:-1] # "oll" ← start 생략(=끝), end=-4(=index 1) 전까지, step=-1