프로그래밍/코딩 테스트, 더 이상 미룰 수 없다

[코딩 테스트, 더 이상 미룰 수 없다] 코테 오답노트(1)

d 0_0 b 2026. 6. 30. 16:26

1. DFS/BFS 문제: 거리두기 확인하기

실수 1. 함수 호출 인자 개수 불일치

잘못 쓴 코드:

dfs((i, j, place, 1))

함수 정의:

def dfs(x, y, place, depth):

dfs는 인자 4개를 받는데, 튜플 1개를 넘긴 형태였다.

수정:

dfs(i, j, place, 1)

또는 더 깔끔하게는 depth를 0부터 시작한다.

dfs(i, j, place, 0)

실수 2. 재귀 결과를 부모 함수에서 받지 않음

잘못 쓴 코드:

dfs(nx, ny, place, depth + 1)

이렇게 하면 안쪽 DFS에서 False를 반환해도 바깥 DFS가 그 값을 모른다.

수정:

if dfs(nx, ny, place, depth + 1) == False:
    return False

DFS에서 위반을 발견했으면 그 결과를 끝까지 전달해야 한다.

기억할 것:

재귀 안에서 찾은 False는 부모 호출까지 return 해야 한다.

실수 3. visited를 전체 place에서 한 번만 사용함

잘못된 흐름:

visited = [[False] * m for _ in range(n)]

for 모든 P:
    dfs()

이렇게 하면 첫 번째 P에서 방문한 좌표가 두 번째 P 탐색에도 영향을 줄 수 있다.

수정:

for i in range(n):
    for j in range(m):
        if place[i][j] == 'P':
            visited = [[False] * m for _ in range(n)]
            visited[i][j] = True
            dfs(i, j, place, 0)

이 문제는 각 P를 기준으로 거리 2까지만 탐색하는 문제이므로, visited는 P마다 새로 만드는 게 안전하다.


실수 4. 파티션을 변수로 기억하려고 함

처음에는 이런 식으로 생각했다.

if place[nx][ny] == 'X':
    partition = True

하지만 이 문제에서는 그럴 필요가 없다.

X는 벽이다. 만나면 그 방향 탐색을 끊으면 된다.

if place[nx][ny] == 'X':
    continue

기억할 것:

격자 탐색에서 벽은 상태로 들고 가지 말고, 보통 continue로 막는다.

실수 5. 문자 대소문자 주의

문제의 값은 보통 이렇게 주어진다.

'P', 'O', 'X'

잘못 쓰면 오류 또는 오답이 난다.

if place[i][j] == p:   # p라는 변수 없음
if place[nx][ny] == 'x':  # 문제에서는 'X'

수정:

if place[i][j] == 'P':
if place[nx][ny] == 'X':

실수 6. 거리 2 케이스를 놓침

꼭 체크해야 하는 케이스:

P O P

맨해튼 거리 2이고 중간이 O라서 위반이다.

대각선도 체크해야 한다.

P O
O P

이것도 맨해튼 거리 2이고 파티션이 없으면 위반이다.

시험에서 직접 만들어볼 테스트:

# 바로 옆 P: 위반
["PPOOO",
 "OOOOO",
 "OOOOO",
 "OOOOO",
 "OOOOO"]

# 거리 2, 중간 O: 위반
["POPOO",
 "OOOOO",
 "OOOOO",
 "OOOOO",
 "OOOOO"]

# 거리 2, 중간 X: 통과
["PXPOO",
 "OOOOO",
 "OOOOO",
 "OOOOO",
 "OOOOO"]

# 대각선 거리 2: 위반
["POOOO",
 "OPOOO",
 "OOOOO",
 "OOOOO",
 "OOOOO"]

2. 구현 문제: 주차 요금 계산

실수 1. defaultdict key 정렬 문법

잘못 쓴 코드:

record_dict = sorted(record_dict, lambda key=x:x[0])

문제점:

lambda key=x:x[0]

이 문법이 틀렸다.

수정:

record_dict = dict(sorted(record_dict.items(), key=lambda x: x[0]))

기억할 것:

sorted(딕셔너리.items(), key=lambda x: x[0])
  • x[0]: key 기준 정렬
  • x[1]: value 기준 정렬

실수 2. dict_items는 바로 인덱싱 불가

잘못 쓴 코드:

record_dict.items()[0]

record_dict.items()는 리스트가 아니라 dict_items 객체라서 바로 [0] 접근이 안 된다.

수정:

list(record_dict.items())[0]

다만 보통은 이렇게 순회하는 게 맞다.

for car_num, time_records in record_dict.items():
    print(car_num, time_records)

실수 3. 문자열 시간끼리는 뺄 수 없음

잘못된 생각:

"23:59" - "16:00"

문자열끼리는 뺄 수 없다.

시간은 분으로 바꿔야 한다.

def time_to_minute(time):
    h, m = time.split(":")
    return int(h) * 60 + int(m)

예시:

time_to_minute("16:00")  # 960
time_to_minute("18:00")  # 1080

실수 4. 출차 기록이 없는 경우 처리

입차만 있고 출차가 없으면 23:59에 출차한 것으로 본다.

잘못된 접근:

time_to_minute(time_record[-1])
record_dict[num].remove(-1)

문제점:

  1. time_to_minute(time_record[-1])만 하면 결과를 저장하지 않는다.
  2. remove(-1)은 마지막 요소 삭제가 아니라 값이 -1인 요소 삭제다.
  3. 이 문제에서는 삭제보다 "23:59"를 추가하는 게 훨씬 편하다.

수정:

if len(time_records) % 2 == 1:
    time_records.append("23:59")

기억할 것:

입출차 기록 개수가 홀수면 출차가 없는 것 → "23:59" 추가

실수 5. 입출차가 여러 번일 수 있음

잘못 쓴 코드:

for _ in range(len(record_dict[num])-1):
    time += time_to_minute(record_dict[num][1]) - time_to_minute(record_dict[num][0])

이러면 항상 첫 번째 출차 - 첫 번째 입차만 반복해서 더한다.

예를 들어:

['05:34', '07:59', '22:59', '23:00']

정답 계산:

07:59 - 05:34
+
23:00 - 22:59

수정:

total_time = 0

for i in range(0, len(time_records), 2):
    total_time += time_to_minute(time_records[i + 1]) - time_to_minute(time_records[i])

기억할 것:

입차/출차는 2개씩 묶어서 계산한다.

실수 6. 기본 시간 하드코딩

잘못 쓴 코드:

if time <= 180:

문제의 기본 시간은 fees[0]이다.
입력마다 달라질 수 있으므로 하드코딩하면 안 된다.

수정:

if total_time <= default_time:

실수 7. 추가 요금은 round()가 아니라 올림

잘못 쓴 코드:

round(default_fee + ((time-default_time)/p_time) * p_fee)

문제에서는 단위 시간으로 나누어떨어지지 않으면 올림해야 한다.

수정:

import math

extra_fee = math.ceil((total_time - default_time) / p_time) * p_fee
fee = default_fee + extra_fee

기억할 것:

요금 문제에서 "단위 시간마다" + "초과하면" → 대부분 ceil 사용

3. SQL 문제: 자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기

헷갈린 부분: GROUP BY를 왜 쓰는가?

차량 하나에 여러 대여 기록이 있을 수 있다.

예를 들어 한 차에 대해 이런 기록이 있을 수 있다.

대여중
대여 가능
대여 가능

그냥 조회하면 한 차량이 여러 줄로 나온다.
하지만 정답은 차량 하나당 한 줄이어야 한다.

그래서 CAR_ID 기준으로 묶어야 한다.

GROUP BY CAR_ID

핵심 조건

특정 날짜가 대여 기간 안에 포함되면 대여중이다.

'2022-10-16' BETWEEN START_DATE AND END_DATE

이 조건을 만족하는 기록이 하나라도 있으면 대여중이어야 한다.

그래서 MAX()를 활용한다.

CASE
    WHEN MAX(CASE 
                WHEN '2022-10-16' BETWEEN START_DATE AND END_DATE 
                THEN 1 
                ELSE 0 
             END) = 1
    THEN '대여중'
    ELSE '대여 가능'
END

기억할 것:

하나라도 있으면 true → MAX(CASE WHEN 조건 THEN 1 ELSE 0 END)
전부 만족해야 true → MIN(CASE WHEN 조건 THEN 1 ELSE 0 END)
개수 세기 → SUM(CASE WHEN 조건 THEN 1 ELSE 0 END)

4. 오늘 반복된 문법 실수 모음

lambda 문법

잘못:

lambda key=x:x[0]

수정:

lambda x: x[0]

sorted 문법

잘못:

sorted(record_dict, lambda x: x[0])

수정:

sorted(record_dict.items(), key=lambda x: x[0])

함수 인자 전달

잘못:

dfs((i, j, place, 1))

수정:

dfs(i, j, place, 1)

리스트 마지막 요소 삭제

잘못:

arr.remove(-1)

수정:

arr.pop()

다만 주차 요금 문제에서는 삭제보다 추가가 낫다.

time_records.append("23:59")

딕셔너리 순회

추천 형태:

for key, value in record_dict.items():
    print(key, value)

첫 번째 요소 접근:

list(record_dict.items())[0]

문자열 시간 계산

잘못:

"23:59" - "16:00"

수정:

time_to_minute("23:59") - time_to_minute("16:00")

5. 시험장에서 예외케이스 떠올리는 법

문제를 읽고 바로 이 순서로 체크한다.

1. 최소 케이스

입력이 하나만 있을 때도 되는가?

예:

records = ["16:00 3961 IN"]

출차가 없으므로 23:59 처리해야 한다.


2. 반복 케이스

같은 대상이 여러 번 등장하는가?

예:

['05:34', '07:59', '22:59', '23:00']

첫 번째 입출차만 계산하면 오답이다.


3. 조건이 바뀌는 경계

거리두기 문제:

거리 1 → 무조건 위반
거리 2 → 파티션 여부 확인
거리 3 → 상관 없음

주차 요금 문제:

누적 시간 <= 기본 시간 → 기본 요금
누적 시간 > 기본 시간 → 추가 요금
나누어떨어지지 않음 → 올림

4. 없을 때

  • 출차 기록이 없을 때
  • 대여중 기록이 없을 때
  • 탐색 중 더 이상 갈 곳이 없을 때

이런 경우 기본값을 어떻게 처리할지 정해야 한다.


5. 반환값이 전달되는지

DFS에서 특히 중요하다.

if dfs(...) == False:
    return False

이 패턴을 안 쓰면 안쪽에서 찾은 정답이나 실패가 바깥으로 전달되지 않는다.


6. 오늘 문제에서 가져갈 핵심 패턴

DFS 거리 제한 탐색

def dfs(x, y, depth):
    if depth >= 2:
        return True

    for d in range(4):
        nx = x + dx[d]
        ny = y + dy[d]

        if 범위 밖:
            continue

        if visited[nx][ny]:
            continue

        if board[nx][ny] == 'X':
            continue

        if board[nx][ny] == 'P':
            return False

        visited[nx][ny] = True

        if dfs(nx, ny, depth + 1) == False:
            return False

    return True

딕셔너리 key 기준 정렬

record_dict = dict(sorted(record_dict.items(), key=lambda x: x[0]))

시간 문자열을 분으로 변환

def time_to_minute(time):
    h, m = time.split(":")
    return int(h) * 60 + int(m)

입출차 쌍 계산

if len(time_records) % 2 == 1:
    time_records.append("23:59")

total_time = 0

for i in range(0, len(time_records), 2):
    total_time += time_to_minute(time_records[i + 1]) - time_to_minute(time_records[i])

추가 요금 올림 계산

import math

if total_time <= default_time:
    fee = default_fee
else:
    extra_time = total_time - default_time
    fee = default_fee + math.ceil(extra_time / unit_time) * unit_fee

7. 나의 오늘 실수 요약

오늘 실수는 크게 4가지다.

  1. 재귀 반환값을 부모 호출로 전달하지 않음
  2. 입출차 기록처럼 쌍으로 봐야 하는 데이터를 첫 번째 값만 반복 계산함
  3. 문자열 시간을 숫자로 변환하지 않고 계산하려 함
  4. 정렬, lambda, dict_items, remove/pop 같은 파이썬 기본 문법에서 실수가 남

 

 

1. 입력을 어떤 자료구조로 모을 것인가?
2. 같은 key가 여러 번 나오나?
3. 누적 계산인가, 한 번 계산인가?
4. 빠진 기록이나 기본값이 있나?
5. 정렬 기준은 key인가 value인가?
6. DFS/BFS라면 결과가 return으로 전달되는가?