코드 한 줄의 기록

입사 코딩테스트 합격하려면 꼭 알아야 할 예외 케이스 처리와 디버깅 실전 팁 본문

코딩테스트

입사 코딩테스트 합격하려면 꼭 알아야 할 예외 케이스 처리와 디버깅 실전 팁

CodeByJin 2025. 12. 17. 08:08
반응형

코딩테스트를 조금이라도 풀어본 사람이라면 한 번쯤 이런 경험을 했을 것이다.

“로컬 테스트할 땐 다 통과했는데, 제출만 하면 실패”, “예제 입력은 다 맞는데 채점에서 틀렸다고 뜨는 경우”, “시간 초과는 안 나는데 자꾸 한두 개 테스트만 깨지는 경우”.
이런 상황의 대부분은 예외 케이스 미처리허술한 디버깅 습관에서 나온다.

이 글은 “나도 계속 공부해 나가면서, 동시에 다른 사람에게도 설명하는” 느낌으로, 실제 코딩테스트 준비 과정에서 바로 써먹을 수 있는 예외 케이스 처리 방법과 디버깅 팁을 정리해 본다.

왜 ‘예외 케이스’에서 자꾸 발목을 잡힐까?

문제를 풀다가 기본 로직은 금방 떠오르는데, 제출하면 70~80%에서만 통과하고 몇 개 테스트가 깨지는 경우가 많다. 이때 대부분의 패턴은 다음 둘 중 하나다.

  • 문제에서 “특별히 강조하지 않은 조건”을 놓친 경우
  • 데이터 범위와 극단값(최대/최소)을 신경 쓰지 않은 경우

코딩테스트 문제는 출제자가 “여기에서 자주 틀리더라” 싶은 패턴을 알고 의도적으로 케이스를 넣는다. 그래서 예외 케이스를 잘 잡는 연습만으로도 같은 알고리즘 실력을 가진 사람들 사이에서 한 단계 위로 올라갈 수 있다.

예외 케이스를 잘 처리하기 위해서는 두 가지를 반드시 습관으로 만들면 좋다.

  1. 코드 작성 전, 머릿속/메모장으로 입력 케이스를 직접 설계해 보기
  2. 풀이를 완성한 후, ‘틀리기 쉬운 상황’을 일부러 만들어서 찍어보기

이 두 가지를 코딩테스트 연습할 때마다 의식적으로 반복하면, 자연스럽게 예외를 먼저 떠올리는 사고 방식이 몸에 배게 된다.

코딩테스트에서 자주 등장하는 예외 케이스 유형

예외 케이스라고 해서 특별한 게 아니다. 계속 반복되는 패턴이 있다. 문제를 읽을 때, 코드 짜기 전에 다음 체크리스트를 한 번 훑어보자.

최소/최대 크기(경계값) 케이스

  • 배열/리스트 길이가 0, 1, 2 같은 극단적으로 작은 값일 때
  • (N), (M) 같은 입력의 크기가 문제에서 주어진 최대값일 때
  • 값 자체가 최대 정수, 최소 정수에 가깝게 들어올 때 (예: 10억, -10억)

예시로 정렬 후 인접 원소 차이를 비교하는 문제가 있다면

  • N = 1인 경우: 인접 원소가 아예 없는데 코드에서 for (i in 0 until n-1) 돌리면?
  • N = 2인데 인덱스 접근을 실수하면?

그래서 항상 코드 짜기 전에 이렇게 스스로 질문해보는 습관이 필요하다.

  • “길이가 0이면?”, “길이가 1이면?”, “길이가 2면?”
  • “입력 수가 최대인 경우, 지금 알고리즘 시간복잡도로 버틸 수 있나?”

이 질문만 해봐도 적어도 인덱스 에러나 단순 로직 버그는 많이 줄어든다.

정렬/탐색에서의 동점, 중복 값

  • 점수 순 정렬, 키/몸무게 정렬 등에서 값이 같은 경우(동점) 정렬 기준을 잘못 처리
  • 해시맵/딕셔너리에서 같은 키가 여러 번 들어올 때 누적을 안 하고 덮어쓰기만 할 때

예를 들어 “점수 내림차순, 점수 같으면 이름 사전순”이라고 했는데, 점수만 기준으로 정렬하면 동점일 때 순서가 잘못될 수 있다.
또 “이름별 등장 횟수”를 세는 문제에서, 이미 존재하는 키에 대해 count[name] = 1로 덮어써버리는 실수도 흔하다.

 

이런 문제를 막으려면

  • 문제에서 동점, 중복이 나올 수 있는지 꼭 확인
  • 정렬 기준을 최종 정렬 조건 그대로 구현 (복합 정렬 기준)
  • 해시맵/딕셔너리 사용할 때는 “기존 값에 누적하는지” 항상 의식하기

나누기, 나머지, 음수/0 처리

  • 나누는 값이 0이 될 수 있는지
  • 음수를 다뤄야 할 때, 언어별 나머지 연산 결과 차이

예를 들어 평균 계산할 때, 분모가 0이 되면 안 되는데, 그룹에 속한 원소가 하나도 없는 케이스가 나올 수 있다. 조건에서 “항상 한 명 이상”이라고 보장해 주지 않았다면, 스스로 이 케이스를 생각해야 한다.

또 언어에 따라 (-1 mod 3) 결과가 다를 수 있다. 자바, 파이썬, C++ 등은 대부분 음수 나머지를 허용하지만, 결과값의 부호는 언어마다 정의가 조금씩 다르다. 코딩테스트에서 흔히 나오는 패턴은 아니지만, 그래프/수학 관련 문제에서 슬쩍 낚싯줄처럼 등장하는 경우가 있다.

문자열 처리에서의 공백, 빈 문자열, 줄바꿈

  • 입력이 빈 문자열인 경우
  • 문자열 앞/뒤에 공백이 붙어 있는 경우
  • 줄바꿈이 애매하게 들어오거나, 마지막에 공백 줄이 하나 더 있는 경우

특히 코딩테스트 플랫폼마다 입력 형식이 조금씩 달라서, split(" ") 같은 식으로 고정 공백 기준으로 자르면 연속 공백이나 탭 문자에서 오작동할 수 있다.


언어별로 split 계열 함수의 옵션(정규식인지, 연속 공백 처리 방식 등)을 대략적으로라도 알아두면 예외를 덜 맞는다.

 

연습할 때는 스스로 테스트 케이스를 만들 때 다음을 꼭 섞어보자.

  • 문자열 길이가 0인 입력
  • 공백만 잔뜩 있는 입력 " "
  • 탭 문자, 여러 개의 공백이 섞인 입력

그래프/트리에서의 고립 노드, 단일 노드

  • 연결 요소가 여러 개 있을 때(완전 연결 그래프가 아님)
  • 간선이 하나도 없는 노드가 있을 때
  • 노드가 1개밖에 없는 그래프 (N=1)

예를 들어 DFS/BFS 문제를 풀 때, 방문 배열을 초기화하는 시점, 반복문에서 시작 정점을 어떻게 잡는지에 따라 고립 노드가 빠질 수 있다.

그래서 테스트 케이스를 직접 만들 때는

  • N=1, 간선 0개
  • N이 작고, 간선이 매우 적은(거의 없는) 그래프
  • 여러 연결 요소로 나뉘어진 그래프

이 세 가지는 항상 별도로 확인해 보는 것이 좋다.

예외 케이스를 체계적으로 찾는 체크리스트

코드를 다 짰다고 바로 제출하는 대신, 5분만 투자해서 체크리스트를 돌려보는 습관을 만들어 보자.

다음 질문을 하나하나 스스로에게 던져보면 좋다.

  1. 입력 크기가 최소일 때(0, 1, 2) 코드가 정상 동작하는가?
  2. 입력 크기가 최대일 때 시간복잡도, 메모리가 버티는가?
  3. 정렬/탐색에서 동점, 중복 값이 들어오면 의도한 대로 동작하는가?
  4. 나누기/나머지 연산에서 0이나 음수가 들어와도 안전한가?
  5. 문자열 앞뒤 공백, 빈 문자열, 줄바꿈 케이스도 처리됐는가?
  6. 그래프/트리 문제라면, 고립 노드, 단일 노드 케이스를 처리했는가?
  7. 배열/리스트 인덱스에서 -1, n 같은 잘못된 접근 가능성은 없는가?

처음에는 이걸 전부 생각하는 것이 피곤할 수 있지만, 몇 번만 의식적으로 반복하면 자연스럽게 머릿속에서 자동으로 체크가 돌아간다.
실제로 합격하는 사람들과 아슬아슬하게 떨어지는 사람들의 차이는 이런 “습관”에서 나온다.

디버깅 사고방식: “버그를 찾는 방법”을 연습하자

예외 케이스를 잘 떠올리는 것도 중요하지만, 현실에서는 코드가 이미 틀렸을 때, 어디가 문제인지 빨리 찾는 능력이 훨씬 중요하다.
코딩테스트 디버깅에서 중요한 포인트는 크게 두 가지다.

  • 증상이 아니라 원인에 집중하기
  • “한 번에 고치려는 욕심”을 버리고, 문제를 쪼개서 좁혀 가기

예를 들어, 채점 결과에서 “오답”이 떴다고 할 때 많은 사람이 하는 실수는

  • 전체 로직을 다시 머릿속에서 시뮬레이션하면서 “대충 맞는 것 같은데…” 상태에 빠지는 것
  • 작은 로그를 찍어보지 않고, 감으로 한두 줄 고쳐서 다시 제출해 보는 것

좋은 디버깅 습관은 다음 순서로 진행된다.

  1. 문제가 되는 입력을 하나라도 찾는다.
    • 직접 다양한 케이스를 만들어보다가 깨지는 입력을 찾거나,
    • 로컬에 비슷한 상황을 강제로 만들어 본다.
  2. 그 입력 하나만 가지고 코드를 한 줄씩 따라간다.
    • 중요한 지점마다 출력(log)을 찍어서 중간 상태를 본다.
  3. “실제 값”과 “원래 기대한 값”의 차이가 처음으로 발생하는 지점을 찾는다.
    • 그 지점이 바로 로직이 어긋난 곳이다.

즉, 전체 코드가 막연히 틀린 게 아니라, 어디서부터 잘못됐는지 경계선을 찾는 과정이 디버깅이다.

실전 디버깅 팁: 로그를 “전략적으로” 찍자

온라인 코딩테스트 환경에서는 println이나 System.out.println 같은 출력이 디버깅의 거의 전부다. 이 단순한 출력도 “어디에, 무엇을” 찍느냐에 따라 효율이 완전히 달라진다.

 

“입력 → 중간 상태 → 결과”의 3단계로 찍기

디버깅할 때는 적어도 다음 세 지점을 확인해 보자.

  • 입력을 제대로 읽어왔는지
  • 핵심 로직을 통과한 직후, 중간 결과가 예상과 같은지
  • 최종 출력 직전에 값이 의도한 대로 나왔는지

예문을 들면, 정렬 후 슬라이싱을 하는 문제라면

  • 정렬 직후 배열 상태
  • 슬라이싱한 범위
  • 슬라이싱 결과

이 세 가지만 봐도 상당수 버그를 바로 찾을 수 있다.

 

모든 반복마다 찍지 말고, “경계 지점”만 찍기

for/while 문 안에 매번 로그를 찍으면, 입력이 조금만 커져도 출력이 폭발해서 오히려 디버깅이 힘들어진다.

그래서 다음과 같은 지점을 골라서 찍는 것이 좋다.

  • 첫 번째 반복, 마지막 반복
  • 인덱스가 경계인 지점 (예: 0, n-1, n-2)
  • 조건문이 분기되는 지점(조건이 참일 때/거짓일 때 하나씩)

반복문 안에서 “특정 조건을 만족하는 원소만 출력”하는 식으로 필터링해서 찍어도 좋다.

단계별로 출력 포맷을 정해두기

디버깅할 때 출력 포맷을 대충 찍으면, 나중에 로그를 읽다가 헷갈리기 쉽다. 간단히라도 패턴을 정해 두자.

  • [STEP1], [STEP2] 처럼 단계 번호를 붙이기
  • "before sort: ...", "after sort: ..." 처럼 상황을 구분해서 출력
  • "i=3, val=10" 형태로 인덱스와 값을 같이 출력

이렇게 포맷을 통일하면, 여러 번 디버깅해도 로그를 빠르게 스캔할 수 있다.

시간 초과(TLE) 디버깅: 로직이 맞아도 시간에서 터질 때

많은 경우, 예외 케이스 이전에 시간복잡도 때문에 터지는 실수가 있다. 이때는 단순 로직 디버깅이 아니라, 어디에서 O(N²)이 나오는지 구조를 잡아내는 것이 핵심이다.

체크 포인트는 다음과 같다.

  • 이중 for문(for i in ... for j in ...)이 있는 부분에서, 최악의 경우 반복 횟수를 곱셈으로 계산해 본다.
  • 재귀/DFS/BFS에서 같은 노드를 여러 번 방문하고 있지는 않은지 확인한다.
  • 정렬, 우선순위 큐, 해시맵 등 더 나은 자료구조로 바꿀 수 있는 부분이 있는지 본다.

시간 초과 디버깅도 결국은 “어디서 문제인지 좁혀 가는 작업”이다. 입력을 조금씩 키워보면서, 어느 순간부터 급격히 느려지는지 체감해 보는 것도 도움이 된다.

입사 코딩테스트용 루틴: 문제 한 개 풀 때 연습 루트

실전에서 긴장하지 않으려면, 평소 연습할 때부터 같은 루틴으로 움직이는 것이 좋다. 예를 들어 다음과 같은 흐름을 몸에 익혀 보자.

  1. 문제를 읽으면서 입력/출력 예시를 직접 손으로 다시 적어본다.
  2. 바로 코드를 치지 말고, 간단한 케이스 + 극단 케이스를 메모장에 먼저 써 본다.
    • 최소 입력, 최대 입력
    • 동점/중복
    • 공백/빈값
  3. 큰 흐름을 종이에 간단히 쓰고 나서 코드를 구현한다.
  4. 구현이 끝나면, 아까 적어 둔 테스트 케이스로 로컬에서 직접 돌려 본다.
  5. 한 번에 맞으면 좋지만, 틀리면 디버깅 모드로 전환한다.
    • 문제 되는 케이스를 찾고
    • 중간 상태를 찍어 보며, 로직이 어긋나는 최초 지점을 찾는다.
  6. 최종적으로 AC(통과)를 받으면, 어디서 헷갈렸는지, 무슨 예외 케이스를 추가로 떠올렸는지를 짧게라도 기록한다.
    • 블로그에 정리하면서, 그때 그때 배운 예외 케이스 패턴을 쌓아가기

이 루틴을 그대로 블로그에 시리즈처럼 정리해 두면, 나중에 다시 볼 때도 좋고 면접 때 “코딩테스트를 어떻게 준비했는지” 설명할 때도 큰 도움이 된다.

블로그용으로 예외 케이스/디버깅 글을 쓸 때의 팁

“나도 공부하면서 정리하고, 다른 사람도 보게 하자”는 컨셉으로 글을 쓸 거라면, 다음 구성을 기준으로 시리즈를 기획해 볼 수 있다.

  • 1편: 예외 케이스 개념 정리 + 공통 패턴 소개
  • 2편: 자료구조별(배열/문자열/그래프) 실전 예외 케이스 모음
  • 3편: 디버깅 기본기 – 로그 찍는 위치, 생각하는 방법
  • 4편: 시간 초과/메모리 초과 디버깅 사례
  • 5편: 코딩테스트 복기 노트 작성법 (틀린 문제 기록하는 법)

각 글마다 실제로 풀었던 문제를 예로 들어

  • 처음에 어떤 예외 케이스를 놓쳤는지
  • 그걸 어떻게 찾아냈는지(어떤 로그를 찍었는지)
  • 다시 풀면 어디에 주의할 것인지

이 세 가지 포인트를 구체적으로 써주면, 보는 사람도 공감하기 쉽고, 작성자 본인도 기억에 오래 남는다.

앞으로 연습하면서 같이 챙겨볼 포인트 정리

마무리로, 입사 코딩테스트를 준비하면서 예외 케이스와 디버깅 쪽에서 계속 의식해야 할 포인트를 다시 한 번 묶어보자.

  • 코드 치기 전에 예외 케이스를 먼저 떠올리는 습관을 들이자.
    • 최소/최대 크기, 동점/중복, 빈 문자열, 고립 노드 등
  • 한 번에 정답을 맞추려 하지 말고, “틀려도 금방 고치면 된다”는 마인드로 디버깅 루틴을 정해 두자.
    • 문제 되는 입력 하나 찾기 → 중간 상태 출력 → 최초로 어긋나는 지점 찾기
  • 디버깅용 출력은 전략적으로 찍자.
    • 입력, 핵심 중간 상태, 최종 결과
    • 경계 인덱스, 조건 분기 시점
  • 연습이 끝나면, 그날 틀렸던 문제의 예외 케이스와 디버깅 과정을 블로그에 한 번씩 정리하자.
    • “오늘도 감으로 풀다가 예외 케이스 맞았다”라는 기록이 몇 번만 쌓여도, 다음부터는 감으로 안 풀게 된다.

결국 코딩테스트는 단순히 알고리즘 지식만 보는 시험이 아니라, 문제를 꼼꼼히 읽고, 예외 케이스를 스스로 찾아내고, 틀렸을 때 차분하게 원인을 좁혀 가는 실력을 함께 본다.

이 글에서 정리한 예외 케이스 패턴과 디버깅 습관을 연습 때부터 의식적으로 적용해 보면, 실제 입사 코딩테스트에서도 훨씬 안정적으로 점수를 만들어 낼 수 있을 것이다.

앞으로 다른 문제를 풀면서도 “이번 문제에서는 어떤 예외 케이스가 있었나?”, “디버깅할 때 어디부터 확인했더라?”를 하나씩 정리해 나가면, 이 글 자체도 계속 확장해 나갈 수 있다.

이런 식으로 공부 과정을 공유하는 글을 쌓다 보면, 어느 순간에는 “코딩테스트 잘 보는 사람”이 아니라, “코딩테스트를 잘 준비하는 방법을 설명할 수 있는 사람”이 되어 있을 것이다.

 

 

코딩테스트 합격을 위한 변수명과 함수명 짓는 완벽 가이드

대부분의 개발자가 처음 코딩테스트를 준비할 때 간과하기 쉬운 부분이 있습니다. 바로 변수명과 함수명을 짓는 방식입니다. 많은 사람들이 알고리즘 해결 자체에만 집중하다 보니 코드의 가독

byteandbit.tistory.com

 

반응형