https://school.programmers.co.kr/learn/courses/30/lessons/388351
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 분석 및 핵심 로직
문제의 목표는 직원들의 출근 희망 시각과 일주일간의 실제 출근 기록을 비교하여 상품 수령 대상자를 세는 것이다.
핵심 조건:
- 지각 허용: 희망 시각 + 10분까지는 인정
- 시간 포맷: 시(Hour) * 100 + 분(Minute) 형태의 정수 (예: 10시 10분 = 1010)
- 요일 예외: 토, 일요일은 지각해도 상관없음
시간 관련 연산 최적화
시간 계산에서 가장 까다로운 부분은 "60분이 넘어가면 1시간을 올려야 한다"는 점이다. 보통은 몫과 나머지(//, %)를 사용하지만, 정수 형식을 유지한 채 덧셈만으로 처리하는 기법이 있다.
희망시각 + 10을 했을 때, 분(Minute) 부분이 60 이상이면 40을 더한다.- 원리: 10진수 체계에서 100이 되어야 자릿수가 넘어가는데, 시간은 60만 되어도 넘어가야 한다. 그 차이인 40(100-60)을 강제로 더해주면 100단위가 올라가며 시간 자릿수가 바뀐다.
deadline = schedule + 10
if deadline % 100 >= 60:
deadline += 40
zip() 함수
이 문제에서는 schedules(희망 시각 배열)와 timelogs(실제 기록 2차원 배열)의 길이가 같다. 즉, 0번 직원의 희망 시각은 schedules[0], 실제 기록은 timelogs[0]에 있다.
초심자는 보통 인덱스(i)를 사용해 접근한다.
for i in range(len(schedules)):
target = schedules[i]
log = timelogs[i]
# ... 로직 수행
하지만 파이썬에서는 zip()을 사용하는 것이 훨씬 효율적이고 직관적이다.
zip()의 동작 원리
zip은 옷의 지퍼처럼 두 개 이상의 리스트에서 같은 인덱스에 있는 요소끼리 묶어서 튜플(tuple) 형태로 반환해준다.
# zip을 사용한 파이썬 스타일
for schedule, logs in zip(schedules, timelogs):
# schedule에는 schedules[i] 값이,
# logs에는 timelogs[i] 값이 자동으로 들어온다.
# ... 로직 수행
- 장점 1:
i라는 인덱스 변수를 관리할 필요가 없다. - 장점 2: 코드의 가독성이 높아진다. "스케줄과 로그를 묶어서 본다"는 의도가 명확하다.
- 장점 3: 내부적으로 최적화되어 있어
range()와 인덱싱을 쓰는 것보다 미세하게 빠르다.
효율적인 중단: Short-circuit
직원이 상품을 받으려면 "평일 중 단 하루라도 지각하면 안 된다"는 조건이 있다. 이를 반대로 말하면 "지각한 날이 하루라도 발견되면, 남은 요일은 검사할 필요가 없다"는 뜻이다.
이것을 Short-circuit(단축 평가)라고 하며, 불필요한 연산을 막는 핵심 테크닉이다.
fail_count = 0
for day in logs:
if day > deadline:
fail_count += 1
if fail_count == 0:
answer += 1
월요일에 이미 지각했는데 금요일까지 확인하는 것은 자원 낭비다.
is_late = False
for day_log in logs:
if day_log > deadline:
is_late = True
break
break를 만나면 남은 반복을 즉시 종료한다.
최종 솔루션 코드
위에서 설명한 zip, +40 연산, Short-circuit 그리고 주말 제외 로직을 모두 통합한 코드다.
def solution(schedules, timelogs, startday):
answer = 0
# 1. 검사해야 할 요일(평일)의 인덱스만 미리 계산 (Pre-calculation)
# 매번 (startday + j) % 7 계산을 하지 않기 위함
check_indices = []
for j in range(7):
# 요일 계산: (시작요일 + 경과일 - 1) % 7 + 1
day = (startday + j - 1) % 7 + 1
if day != 6 and day != 7: # 토(6), 일(7)이 아니면
check_indices.append(j)
# 2. zip을 활용하여 두 리스트를 동시에 순회
for schedule, logs in zip(schedules, timelogs):
# 3. 시간 계산 (+40 Trick)
deadline = schedule + 10
if deadline % 100 >= 60:
deadline += 40
is_late = False
# 4. 미리 구해둔 '평일 인덱스'만 골라서 확인
for idx in check_indices:
if logs[idx] > deadline:
is_late = True
break # 5. Short-circuit: 지각 확정 시 즉시 중단
# 지각하지 않았다면 카운트 증가
if not is_late:
answer += 1
return answer
요약
zip()활용: 인덱스(i)로 접근하기보다, 데이터를 직접 묶어서 순회하라.- Short-circuit (
break): 결과가 확정되는 순간 반복을 멈춰라. - 전처리 (Pre-calculation): 반복문 안에서 매번 계산하지 말고, 공통된 조건(요일 인덱스 등)은 밖에서 미리 계산해라.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!