Programmers Coding Test · Day 14 · Python
Day 14
파이썬 반복문과 리스트 5문제 풀이
슬라이싱, 두 리스트 동시 순회, 누적 합, 인덱스와 값의 차이를 직접 작성한 코드의 수정 과정과 함께 정리했습니다.
오늘 문제들은 모두 리스트를 순서대로 다룬다는 공통점이 있지만, 필요한 도구는 조금씩 달랐다. 결과 리스트를 새로 만드는 문제에서는 슬라이싱과 리스트 컴프리헨션이 잘 맞았고, 조건을 만족하는 순간 계산을 끝내야 하는 문제에서는 일반 for문과 조기 반환이 더 자연스러웠다.
range(s, e + 1)은 범위를 직접 제한하므로 같은 조건을 다시 if로 검사할 필요가 없다.
문제 및 공식 링크
| 순서 | 문제 | 핵심 개념 |
|---|---|---|
| 1 | 홀수 vs 짝수 | 인덱스의 홀짝, max() |
| 2 | 5명씩 | 슬라이싱의 간격 |
| 3 | 할 일 목록 | enumerate(), zip() |
| 4 | n보다 커질 때까지 더하기 | 누적 합, 조기 반환 |
| 5 | 수열과 구간 쿼리 1 | 인덱스와 값, 구간 반복 |
1. 홀수 vs 짝수
첫 번째 원소를 1번 원소라고 할 때 홀수 번째 원소의 합과 짝수 번째 원소의 합 중 더 큰 값을 반환하는 문제다. 사람의 홀수 번째 위치는 파이썬의 짝수 인덱스 0, 2, 4, ...에 해당한다.
내 풀이
def solution(num_list):
answer1 = 0
answer2 = 0
for i in range(len(num_list)):
if i % 2 == 0:
answer1 += num_list[i]
else:
answer2 += num_list[i]
return answer1 if answer1 > answer2 else answer2
이 풀이는 정확한 정답이다. 인덱스가 짝수면 문제에서 말하는 홀수 번째 원소이고, 인덱스가 홀수면 짝수 번째 원소다. 두 합이 같을 때는 answer2를 반환하지만 두 값이 같으므로 결과에는 문제가 없다.
같은 효율로 조금 더 간단하게
def solution(num_list):
odd_sum = 0
even_sum = 0
for i, num in enumerate(num_list):
if i % 2 == 0:
odd_sum += num
else:
even_sum += num
return max(odd_sum, even_sum)
enumerate()로 인덱스와 값을 함께 받고, 마지막 비교는 max()에 맡겼다. 시간 복잡도는 O(N), 결과 합계 외에 별도 리스트를 만들지 않으므로 추가 공간은 O(1)이다.
슬라이싱을 사용한 짧은 풀이
def solution(num_list):
return max(sum(num_list[::2]), sum(num_list[1::2]))
검산: [4, 2, 6, 1, 7, 6]의 홀수 번째 합은 17, 짝수 번째 합은 9이므로 결과는 17이다.
2. 5명씩
이름을 앞에서부터 5명씩 묶고 각 그룹의 첫 번째 사람을 반환하는 문제다. 필요한 인덱스는 0, 5, 10, ...이다.
내 풀이
def solution(names):
answer = names[::5]
return answer
수정할 오류가 없는 정답이다. 슬라이싱의 형태는 [start:stop:step]이고, 시작과 끝을 생략한 [::5]는 처음부터 끝까지 5칸 간격으로 선택한다.
직접 반환하기
def solution(names):
return names[::5]
결과를 새 리스트로 반환해야 하는 문제이므로 슬라이싱이 만드는 새 리스트가 문제의 목적과 잘 맞는다. 공식 예제에서는 0번의 "nami"와 5번의 "vex"가 선택된다.
3. 할 일 목록
todo_list와 같은 위치의 finished 값을 확인해 아직 끝내지 않은 일만 순서대로 모으는 문제다.
내 풀이
def solution(todo_list, finished):
answer = []
for i in range(len(todo_list)):
if finished[i] == False:
answer.append(todo_list[i])
return answer
이 코드도 정확한 정답이다. 인덱스 i를 이용해 두 리스트의 같은 위치를 연결했다. 다만 불리언 값이 거짓인지 확인할 때는 == False보다 not을 쓰면 의도가 더 자연스럽게 읽힌다.
enumerate()로 정리한 풀이
def solution(todo_list, finished):
answer = []
for i, task in enumerate(todo_list):
if not finished[i]:
answer.append(task)
return answer
zip()과 리스트 컴프리헨션
def solution(todo_list, finished):
return [task for task, is_finished in zip(todo_list, finished)
if not is_finished]
zip()은 두 리스트의 같은 위치에 있는 값을 한 쌍씩 묶는다. 인덱스가 필요 없는 이 문제에서는 할 일과 완료 여부를 직접 받는 풀이가 가장 간결하다. 다만 두 입력의 길이가 다르면 짧은 쪽에서 멈춘다는 특성이 있으며, 이 문제에서는 두 배열의 위치가 대응하므로 그대로 사용할 수 있다.
검산: [True, False, True, False]에서는 두 번째와 네 번째 할 일만 결과에 들어간다.
4. n보다 커질 때까지 더하기
배열의 원소를 앞에서부터 누적해 더하다가 합이 n보다 커지는 순간의 합을 반환하는 문제다.
처음 작성한 코드
def solution(numbers, n):
return [sum(numbers[i]) for i, num in enumerate(numbers)
if sum(numbers[i]) > n]
numbers[i]는 리스트가 아니라 정수 하나다. 따라서 sum(numbers[i])는 TypeError를 발생시킨다.n을 넘은 합계 하나를 반환해야 한다.sum(numbers[:i + 1])로 문법만 고치면 매 단계마다 앞부분을 새로 만들고 다시 합산해 최악의 경우 O(N²)이 된다.누적 합을 사용한 기본 풀이
def solution(numbers, n):
total = 0
for num in numbers:
total += num
if total > n:
return total
이전 합을 total에 보관하므로 각 원소를 한 번만 더한다. 조건을 만족하는 순간 바로 반환해 뒤쪽 원소도 확인하지 않는다. 시간 복잡도는 실제로 확인한 원소 수를 K라고 할 때 O(K), 추가 공간은 O(1)이다.
itertools.accumulate()를 사용한 풀이
from itertools import accumulate
def solution(numbers, n):
return next(total for total in accumulate(numbers) if total > n)
accumulate()는 누적 합을 하나씩 생성하고, next()는 조건을 만족하는 첫 값을 꺼낸다. 문제 조건상 전체 합은 반드시 n보다 크므로 기본값은 필요 없다. 처음 배우는 단계에서는 일반 반복문 풀이가 흐름을 더 잘 보여준다.
검산: [34, 5, 71, 29, 100, 34]를 차례로 더하면 34, 39, 110, 139가 되고 123을 처음 넘은 139를 반환한다.
5. 수열과 구간 쿼리 1
각 쿼리 [s, e]마다 s ≤ i ≤ e를 만족하는 모든 인덱스의 값에 1을 더하는 문제다.
처음 작성한 코드
def solution(arr, queries):
for i in arr:
for s, e in queries:
if i >= s and e >= i:
arr[i] += 1
return arr
for i in arr에서 i는 0, 1, 2 같은 위치가 아니라 배열에 저장된 실제 값이다. 그 값을 다시 arr[i]의 인덱스로 쓰면 범위를 벗어나거나 엉뚱한 원소를 수정할 수 있다.
처음 생각한 흐름을 유지한 수정 풀이
def solution(arr, queries):
for i in range(len(arr)):
for s, e in queries:
if s <= i <= e:
arr[i] += 1
return arr
인덱스 전체를 순회하면서 각 쿼리 범위에 포함되는지 확인하는 방식이다. 원래 의도를 그대로 살린 정답이지만 배열의 모든 인덱스와 모든 쿼리를 비교하므로 시간 복잡도는 O(NQ)다.
필요한 구간만 방문하는 풀이
def solution(arr, queries):
for s, e in queries:
for i in range(s, e + 1):
arr[i] += 1
return arr
s와 끝점 e를 먼저 정한다.range()는 끝값을 포함하지 않으므로 e + 1까지 지정한다.range(s, e + 1)에서 나오는 모든 i는 처음부터 s ≤ i ≤ e를 만족하므로 같은 조건을 다시 검사할 필요가 없다.이 방식의 반복 횟수는 각 쿼리 길이의 합인 O(Σ(e - s + 1))이다. 모든 범위가 배열 전체라면 O(NQ)와 같지만, 짧은 구간이 많을수록 불필요한 비교를 줄인다.
검산: [0, 1, 2, 3, 4]에 [[0, 1], [1, 2], [2, 3]]을 차례로 적용하면 최종 결과는 [1, 3, 4, 4, 4]다.
풀이별 복잡도 정리
| 문제 | 시간 | 추가 공간 | 핵심 |
|---|---|---|---|
| 홀수 vs 짝수 | O(N) | O(1) | 두 합만 누적 |
| 5명씩 | O(N) | O(N) | 약 N/5개의 결과 생성 |
| 할 일 목록 | O(N) | O(K) | 미완료 K개 저장 |
| n보다 커질 때까지 더하기 | O(K) | O(1) | 조건 충족 즉시 반환 |
| 수열과 구간 쿼리 1 | O(구간 길이의 합) | O(1) | 필요한 인덱스만 수정 |
실수 방지 체크리스트
zip()으로 값을 직접 받을 수 있는지 확인한다.sum()에는 정수 하나가 아니라 반복 가능한 값의 묶음을 전달한다.for i in arr의 i는 인덱스가 아니라 값이라는 점을 확인한다.range()에서 끝점을 포함해야 한다면 1을 더한다.같이 보면 좋은 자료
이번 다섯 문제를 풀면서 슬라이싱과 리스트 컴프리헨션이 항상 더 좋은 답은 아니라는 점을 확인했다. 새 리스트가 필요한 문제에서는 간결한 문법이 잘 맞지만, 합이 기준을 넘는 순간 멈춰야 할 때는 누적 변수와 조기 반환이 더 정확하다. 마지막 구간 쿼리 문제에서 값과 인덱스를 구분하고 반복 범위 자체로 조건을 표현한 과정은 이후 배열 문제에서도 계속 사용할 수 있는 기본기가 된다.
'AI > Coding_Test' 카테고리의 다른 글
| Day 13) 프로그래머스 파이썬 슬라이싱 3문제 풀이 (0) | 2026.07.21 |
|---|---|
| Day 12) 프로그래머스 파이썬 슬라이싱 5문제 풀이 (0) | 2026.07.20 |
| Day 10) 프로그래머스 파이썬 문자열 5문제 풀이 (0) | 2026.07.17 |
| Day 10)프로그래머스 파이썬 풀이: 과일 장수, 소수 만들기, 오픈채팅방, 개미 군단, 컨트롤 제트 (0) | 2026.07.15 |
| Day 9) 프로그래머스 문자열 문제: 리스트 컴프리헨션, zip, 슬라이싱, 접미사 풀이 정리 (0) | 2026.07.14 |