| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 알고리즘
- 가비지컬렉션
- 클린코드
- 예외처리
- 객체지향
- 프로그래밍기초
- 자바공부
- Java
- 파이썬
- 백준
- 알고리즘공부
- 자료구조
- 코딩공부
- 개발공부
- 개발자팁
- JVM
- 메모리관리
- HashMap
- 자바기초
- 자바개발
- 자바
- 정렬
- 프로그래머스
- 개발자취업
- 자바프로그래밍
- 코딩인터뷰
- 멀티스레드
- 코딩테스트준비
- 코딩테스트
- 코딩테스트팁
- Today
- Total
코드 한 줄의 기록
코딩테스트 입출력 처리와 파싱 노하우: 실전 팁과 주의사항 본문
코딩테스트를 준비하면서 알고리즘과 자료구조는 열심히 공부하는데, 정작 입출력 처리에서 자꾸 실수하는 경험 없으신가요? 저도 처음에는 문제를 풀고도 입출력 형식을 잘못 읽거나 파싱 과정에서 버그가 생겨서 "틀렸습니다"를 받곤 했습니다. 지금까지 여러 회사의 코딩테스트를 경험하면서 느낀 것은, 깔끔한 입출력 처리가 코딩테스트 점수에 상당한 영향을 미친다는 것입니다.
이 글에서는 제가 실제로 코딩테스트를 준비하면서 경험한 입출력 처리와 파싱의 노하우를 정리해보려고 합니다. 단순한 이론이 아니라, 실전에서 자주 만나는 상황들과 그에 대한 해결책들을 함께 살펴보겠습니다.
기본이 가장 중요: 입력 형식 정확히 읽기
코딩테스트에서 첫 번째 실수가 바로 입력 형식을 제대로 읽지 않는 것입니다. "첫 줄에 정수 N이 주어진다"고 했을 때, 이것이 한 줄에 하나의 정수만 있다는 뜻인지, 아니면 여러 개가 있을 수도 있다는 뜻인지 확실히 해야 합니다.
실제로 제가 경험한 사례를 들어보겠습니다. 한 문제에서 "다음 줄부터 N개의 정수가 공백으로 구분되어 주어진다"고 했는데, 저는 각 줄마다 하나의 정수가 있다고 잘못 이해했습니다. 그 결과 첫 번째 테스트 케이스부터 틀렸습니다. 이런 실수를 피하기 위해서는 입력 예시를 매우 꼼꼼히 봐야 합니다.
입력 형식 읽기 체크리스트
- 몇 개의 줄에 데이터가 분산되어 있는가?
- 각 줄에 몇 개의 데이터가 있는가?
- 데이터들 사이의 구분자가 무엇인가?
- 마지막 줄 다음에 줄바꿈이 있는가?
이런 식으로 명확하게 정리하면 코드를 작성할 때 실수를 줄일 수 있습니다.
프로그래밍 언어별 입력 읽기의 차이점
Java에서의 입력 처리
Java로 코딩테스트를 준비한다면 Scanner와 BufferedReader 중 어떤 것을 쓸지부터 결정해야 합니다. 보통 Scanner는 사용하기 편하지만 속도가 느리고, BufferedReader는 빠르지만 예외 처리가 필요합니다.
저는 시간 제한이 중요한 문제에는 BufferedReader를 사용합니다.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
int n = Integer.parseInt(line);
여러 개의 숫자를 한 줄에서 읽어야 할 때는
String[] parts = br.readLine().split(" ");
int[] arr = new int[parts.length];
for (int i = 0; i < parts.length; i++) {
arr[i] = Integer.parseInt(parts[i]);
}
또는 더 간단하게
int[] arr = Arrays.stream(br.readLine().split(" "))
.mapToInt(Integer::parseInt)
.toArray();
실무에서도 같은 방식을 사용하기 때문에, 코딩테스트에서 이런 패턴에 익숙해지는 것이 나중에도 도움이 됩니다.
Python에서의 입력 처리
Python은 입력 처리가 매우 간단합니다.
n = int(input())
arr = list(map(int, input().split()))
여러 줄을 한 번에 읽을 수도 있습니다.
n, m = map(int, input().split())
Python의 장점은 입력 처리에 시간을 덜 들인다는 것입니다. 하지만 주의할 점은 input() 함수가 줄바꿈 문자를 자동으로 제거한다는 것입니다. 만약 줄바꿈을 포함해서 처리해야 한다면 별도로 처리해야 합니다.
까다로운 입력 형식 처리하기
가변 길이 입력 처리
가장 헷갈리는 부분이 입력의 개수가 미리 정해지지 않은 경우입니다.
1 2 3 4 5
이 경우 몇 개의 숫자가 주어질지 미리 알 수 없습니다.
String line = br.readLine();
int[] arr = Arrays.stream(line.split(" "))
.mapToInt(Integer::parseInt)
.toArray();
또는 Python에서
arr = list(map(int, input().split()))
특수 문자가 포함된 입력
입력에 괄호나 쉼표 같은 특수 문자가 포함되어 있을 때가 있습니다.
(1,2) (3,4) (5,6)
이런 경우 단순히 공백으로 split 하면 괄호와 쉼표가 남아있게 됩니다. 저는 정규표현식(regex)을 사용해서 처리합니다.
String line = br.readLine();
String[] parts = line.replaceAll("[^0-9\\s]", "").split("\\s+");
이것은 숫자와 공백을 제외한 모든 문자를 제거하는 방식입니다. 하지만 더 안전한 방법은 정규표현식으로 정확한 패턴을 찾는 것입니다.
Pattern p = Pattern.compile("\\((\\d+),(\\d+)\\)");
Matcher m = p.matcher(line);
List<int[]> pairs = new ArrayList<>();
while (m.find()) {
pairs.add(new int[]{Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2))});
}
문자열 입력에서 공백 처리
실수하기 쉬운 부분이 문자열 입력입니다. "문자열이 주어진다"고 했을 때, 공백이 있는 문자열인지 없는 문자열인지 구분해야 합니다.
공백이 없는 문자열
hello
공백이 있는 문자열
hello world
공백이 있는 문자열을 split() 하면 여러 개로 쪼개지므로, 이 경우 그냥 readLine()으로 통째로 읽어야 합니다.
파싱 과정에서의 자주 하는 실수들
실수 1: Off-by-one 에러
입력에서 인덱스를 처리할 때 자주 나는 실수가 인덱스 시작점입니다. 문제에서 "1부터 N까지"라고 했을 때 배열은 0부터 시작한다는 것을 잊기 쉽습니다.
제가 자주 쓰는 패턴
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n + 1]; // 1부터 n까지 사용하므로 크기를 n+1로
for (int i = 1; i <= n; i++) {
arr[i] = Integer.parseInt(br.readLine());
}
실수 2: 데이터 타입 오버플로우
입력 값의 범위를 꼭 확인해야 합니다. 예를 들어 최대값이 10억 이상이면 int 대신 long을 사용해야 합니다. 저는 항상 문제에서 주어진 범위를 명시적으로 주석에 적어둡니다.
int n = Integer.parseInt(br.readLine()); // 1 <= n <= 10^5
long result = 0; // 결과값이 10^9를 넘을 수 있음
실수 3: 문자열 인코딩 문제
한글이 포함된 입력을 처리할 때는 인코딩을 신경 써야 합니다.
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in, StandardCharsets.UTF_8)
);
실수 4: 개행 문자 처리
파일의 마지막에 예상치 못한 개행 문자가 있을 수 있습니다. 문자열을 읽은 후에는 trim()으로 공백을 제거하는 것이 안전합니다.
String input = br.readLine().trim();
효율적인 파싱을 위한 팁
팁 1: 정규표현식 활용
복잡한 입력 형식일수록 정규표현식이 도움이 됩니다. 하지만 정규표현식을 컴파일하는 데 시간이 걸리므로, 반복문 내에서 여러 번 사용할 때는 미리 컴파일해두는 것이 좋습니다.
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(input);
while (m.find()) {
int num = Integer.parseInt(m.group());
// 처리
}
팁 2: 미리 파싱 함수 만들기
자주 사용하는 파싱 패턴은 미리 함수로 만들어두면 실수를 줄일 수 있습니다.
static int[] readIntArray(BufferedReader br, int size) throws IOException {
int[] arr = new int[size];
String[] parts = br.readLine().split(" ");
for (int i = 0; i < size; i++) {
arr[i] = Integer.parseInt(parts[i]);
}
return arr;
}
static int[][] read2DArray(BufferedReader br, int rows, int cols) throws IOException {
int[][] arr = new int[rows][cols];
for (int i = 0; i < rows; i++) {
String[] parts = br.readLine().split(" ");
for (int j = 0; j < cols; j++) {
arr[i][j] = Integer.parseInt(parts[j]);
}
}
return arr;
}
팁 3: 입력 검증
본인이 파싱한 데이터가 문제의 조건을 만족하는지 확인해보세요. 특히 배열의 길이나 값의 범위 같은 것들입니다.
assert arr.length == n : "배열 길이가 일치하지 않습니다";
for (int x : arr) {
assert x >= 1 && x <= 1000 : "값이 범위를 벗어났습니다";
}
출력 형식 처리
공백과 줄바꿈의 위치
"N개의 정수를 공백으로 구분해서 출력한다"고 했을 때, 마지막 정수 뒤에 공백이 있으면 안 됩니다. 보통의 온라인 저지는 공백을 무시하지만, 엄격한 채점 시스템도 있습니다.
안전한 방법
for (int i = 0; i < arr.length; i++) {
if (i > 0) System.out.print(" ");
System.out.print(arr[i]);
}
System.out.println();또는
System.out.println(String.join(" ", arr));Python에서
print(' '.join(map(str, arr)))
소수점 처리
실수를 출력할 때는 소수점 자릿수를 정확히 맞춰야 합니다. "소수점 이하 2자리까지 출력"이라고 했다면
System.out.printf("%.2f%n", result);Python에서
print(f"{result:.2f}")디버깅 팁
입출력에 관한 버그가 의심될 때는
- 입력값 그대로 출력해보기: 파싱이 제대로 되었는지 확인
- 작은 예제로 테스트: 직접 만든 간단한 입력으로 테스트
- 엣지 케이스 확인: n=1일 때, 최댓값일 때 등등
- 온라인 저지의 정확한 채점 메시지 읽기: "틀렸습니다", "출력 형식 오류" 등으로 구분됨
예시
System.out.println("n = " + n);
System.out.println("arr = " + Arrays.toString(arr));
각 온라인 저지의 특성 이해하기
온라인 저지마다 입출력 처리 방식이 조금 다를 수 있습니다.
백준(Baekjoon)은 매우 엄격합니다. 출력 형식이 조금만 달라도 틀렸다고 판정합니다. 특히 줄바꿈이 매우 중요하므로, 마지막 답 다음에 반드시 println()을 해야 합니다.
프로그래머스(Programmers)는 일반적으로 더 유연합니다. 많은 경우 공백이나 줄바꿈을 자동으로 처리해줍니다.
코드업(CodeUp)이나 다른 플랫폼들도 각각의 특성이 있으니, 여러 번 제출하다 보면 파악할 수 있습니다.
실전 연습: 복잡한 입력 처리하기
실제로 경험한 입력 형식이 복잡한 문제 예제를 들어보겠습니다.
3 2
1 2 3
2 1
1 3
이 경우
- 첫 줄: n(정점 수), m(간선 수)
- 둘째 줄: n개의 정점 값
- 다음 m개 줄: 각각 간선 정보
코드로 처리하면
String[] firstLine = br.readLine().split(" ");
int n = Integer.parseInt(firstLine[0]);
int m = Integer.parseInt(firstLine[1]);
int[] vertices = Arrays.stream(br.readLine().split(" "))
.mapToInt(Integer::parseInt)
.toArray();
int[][] edges = new int[m][2];
for (int i = 0; i < m; i++) {
String[] parts = br.readLine().split(" ");
edges[i][0] = Integer.parseInt(parts[0]);
edges[i][1] = Integer.parseInt(parts[1]);
}
입출력과 파싱이 화려한 알고리즘은 아니지만, 제대로 하지 못하면 아무리 좋은 풀이도 올바른 결과를 낼 수 없습니다. 저도 처음에는 이 부분을 간과했다가 몇 번의 실패를 겪었지만, 이제는 매 문제마다 입출력 형식을 명확히 파악하고 코드를 작성합니다.
코딩테스트 준비를 하시면서 입출력에서 실수를 하셨다면, 그것은 결코 부끄러운 일이 아닙니다. 오히려 그런 경험들이 쌓이면서 더욱 견고한 프로그래밍 실력을 갖추게 되는 것입니다. 이 글이 여러분의 코딩테스트 준비에 조금이나마 도움이 되길 바랍니다.
입사 코딩테스트 합격하려면 꼭 알아야 할 예외 케이스 처리와 디버깅 실전 팁
코딩테스트를 조금이라도 풀어본 사람이라면 한 번쯤 이런 경험을 했을 것이다.“로컬 테스트할 땐 다 통과했는데, 제출만 하면 실패”, “예제 입력은 다 맞는데 채점에서 틀렸다고 뜨는 경우
byteandbit.tistory.com
'코딩테스트' 카테고리의 다른 글
| 코딩테스트 한 문제를 여러 풀이로 접근하기 - 실무적 해석력 키우기 (0) | 2025.12.27 |
|---|---|
| 완전탐색 vs 그리디 vs 백트래킹: 코딩테스트 알고리즘 완벽 가이드 (0) | 2025.12.21 |
| 입사 코딩테스트 합격하려면 꼭 알아야 할 예외 케이스 처리와 디버깅 실전 팁 (0) | 2025.12.17 |
| 코딩테스트 합격을 위한 변수명과 함수명 짓는 완벽 가이드 (0) | 2025.12.16 |
| 입사 코딩테스트 준비할 때 ‘주석’과 ‘가독성’ 좋은 코드 작성 실전 팁 (0) | 2025.12.15 |