개발
[백준] 2204번 - 도비의 난독증 테스트

문제 탐색하기
1) 문제 분석
테스트케이스 정수 : n (단어의 개수)
대소문자를 구분하지 않고, 사전순으로 가장 앞에 있는 단어 출력
n개의 만큼 문자열 입력
0을 입력하면 종료
2) 가능한 시간복잡도
(1) 입력 처리
테스트케이스 입력 : O(T+1)- T : 테스트케이스 입력 횟수 (종료 조건 포함)
테스트케이스 별 단어 입력 : O(N)- N : 단어의 개수
O(T+1) + O(N) = O(T + N)
(2) 반복문 계산 : O(T)
(3) 단어 추출 및 변환, 정렬
추출 : O(N)
변환 : O(N)
정렬 : O(N log N * L)
O(N) + O(N) + O(N log N * L) = O(N log N * L)
(4) 결과 출력 : O(1)
(5) 전체 시간복잡도
입력 처리 : O(T+N)
반복문 계산 : O(T)
단어 추출 및 변환, 정렬 : O(N) + O(N) + O(N log N * L)
(L의 경우 문자열의 길이)결과 출력 : O(1)-> 총합 : O(T + N + N log N * L + 1) -> O(N log N)
3) 알고리즘 선택 이유
코드 설계하기
1. 실행 구조
1) 입력 처리
한 테스트케이스마다 단어 개수 n이 주어지고, 이후 n개의 단어가 입력된다.
입력을 줄 단위로 split("\n")하여 배열화하고,
shift()를 이용해 앞에서부터 차례대로 테스트케이스 수와 단어들을 처리한다.
0이 입력되면 종료 조건으로 간주하여 while 루프를 종료한다.
2) 단어 수집 및 배열화
각 테스트케이스마다 단어들을 하나의 배열(wordList)에 저장한다.
이 배열은 이후 정렬과 비교에 활용되므로 원본을 유지하면서 정렬할 수 있도록 한다.
정렬 후 첫 번째 요소가 가장 앞선 단어이므로, 이를 출력한다.
3) 정렬 기준 정의 및 사전순 비교
문제 조건에 따라 대소문자 구분 없이 사전순으로 가장 앞서는 단어를 골라야 한다.
JavaScript의 sort()와 localeCompare()를 이용하되,
비교 기준은 모두 **소문자(toLowerCase())**로 변환하여 정렬 기준으로 삼는다.
4) 결과 출력 및 종료 조건 처리
매 테스트케이스마다 정렬된 리스트의 첫 번째 단어를 console.log()로 출력한다.
입력의 첫 줄이 0이면 더 이상 테스트케이스가 없으므로 break 처리로 루프를 종료한다.
2. 고민이 되었던 부분
1) “사전순 비교 기준”
처음에는 단순히 문자열 정렬을 하면 될 것 같았지만,
문제에서 대소문자를 무시해야 한다는 조건을 보고 이를 반영하는 정렬 기준이 필요하다고 판단했다.
JavaScript의 localeCompare는 대소문자 구분 없이 비교 가능하다는 점에서 활용이 가능하지만,
명확하게 하기 위해 .toLowerCase()를 적용해 정렬 기준을 명시적으로 처리했다.
2) “정렬 기준과 출력 형태의 분리”
정렬은 소문자 기준으로 하지만, 출력은 원래 입력된 형태여야 하기 때문에
정렬 기준을 변환된 값이 아닌 원본 문자열로 유지하는 구조가 필요했다.
이를 위해 변환된 배열을 따로 만들기보다는
정렬 기준에만 .toLowerCase()를 적용하고, 출력은 원본 배열을 그대로 사용했다.
정답 코드
// 사용 언어 : Javascript
// 파일 시스템 모듈 불러오기
const fs = require('fs');
// 입력값을 한 줄씩 배열로 저장
const input = fs.readFileSync('/dev/stdin').toString().trim().split("\n");
// 무한 반복문 시작
while (true){
// 1. 단어의 개수 입력받기
const num = Number(input.shift());
// 2. 0이 입력되면 반복문 종료
if (num === 0) {
break;
}
// 3. 단어들을 저장할 배열 생성
const wordList = []
// 4. 입력받은 개수만큼 단어 입력받아 배열에 저장
for (let i = 0; i < num; i++) {
wordList.push(input.shift());
}
// 5. 대소문자 구분 없이 사전순 정렬
wordList.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
// 6. 가장 앞서는 단어 출력
console.log(wordList[0]);
}마무리하며
이번 문제는 겉보기에는 단순한 문자열 정렬 문제처럼 보였지만, 자세히 들여다보면 “정렬 기준”과 “출력 형식”이 분리되어 있다는 점이 핵심이었다.
특히 문제 조건에 따라 대소문자를 구분하지 않는 비교, 하지만 출력은 원본 유지라는 이중 조건을 만족하는 로직을 구현하는 과정에서 단순히 정렬하는 것 이상으로 “문제를 어떻게 이해하고 구현할 것인가”에 대한 고민이 깊어졌다.
또한, JavaScript에서 문자열 비교를 어떤 방식으로 구현할 수 있을지, 라이브러리 함수(localeCompare)나 문자열 처리(toLowerCase)의 조합으로 정확하게 문제 조건을 만족하는 코드를 만드는 과정 자체가 매우 의미 있는 경험이었다.
결과적으로 이번 문제를 통해, 단순히 정답을 맞추는 것보다도 “조건을 얼마나 정확히 이해하고 구현하는가”가 중요하다는 점을 다시금 느꼈고, 앞으로도 조건을 놓치지 않고 꼼꼼하게 구현하는 개발 습관을 유지하고 싶다는 생각을 하게 되었다.