문제 소개
"HH:MM" 형식으로 시간을 나타내는 문자열을 입력받아, 해당 시간에 포함된 숫자들을 재사용하여 만들 수 있는 가장 가까운 다음 시간을 반환하는 JavaScript 함수를 작성해야 합니다. 각 숫자는 제한 없이 몇 번이든 반복해서 사용할 수 있다는 점이 핵심입니다.
예를 들어 함수에 다음과 같은 값이 입력되었다고 가정해 보겠습니다.
입력
const time = '19:34';
출력
const output = '19:39';
출력 설명
숫자 1, 9, 3, 4로 만들 수 있는 다음으로 가장 가까운 시간은 19:39이며, 이는 현재 시간보다 5분 뒤입니다. 같은 숫자로 만들 수 있는 19:33도 존재하지만, 이 시간은 23시간 59분 뒤에 해당하므로 정답이 될 수 없습니다.
해결 아이디어
이 문제는 시간을 구성하는 네 개의 자릿수를 뒤에서부터 앞으로(분의 일의 자리 → 분의 십의 자리 → 시의 일의 자리 → 시의 십의 자리) 하나씩 검사하며, 가능한 한 작은 변화만으로 시간을 앞당기는 그리디(Greedy) 방식으로 해결할 수 있습니다.
구체적인 절차는 다음과 같습니다.
- 네 개의 숫자를 오름차순으로 정렬해 둡니다.
- 분의 일의 자리(d): 현재 값보다 큰 숫자가 있는지 확인하고, 있다면 교체합니다.
- 분의 십의 자리(c): 분은 59까지 표현되므로 5 이하인 숫자 중 현재 값보다 큰 것으로 교체하고, 일의 자리는 최솟값으로 초기화합니다.
- 시의 일의 자리(b): 교체 후 전체 시(hour) 값이 유효 범위를 벗어나지 않는지 확인하며 교체합니다.
- 시의 십의 자리(a): 시는 23까지 표현되므로 2 이하인 숫자 중 현재 값보다 큰 것으로 교체합니다.
- 어떤 자릿수도 더 크게 만들 수 없다면, 모든 자릿수를 최솟값으로 채운 값(예: 11:11)이 하루가 지난 후의 가장 가까운 시간입니다.
구현 코드
위 아이디어를 바탕으로 작성한 코드는 다음과 같습니다.
const time = '19:34';
const findClosestTime = (time = '') => {
// 시간 문자열을 네 개의 숫자로 분리
const [a, b, c, d] = [time[0], time[1], time[3], time[4]].map(x => Number(x));
// 숫자들을 오름차순으로 정렬
const sorted = [a, b, c, d].sort((x, y) => x - y);
// 1) 분의 일의 자리(d)를 더 큰 숫자로 교체
const d2 = sorted.find(x => x > d);
if (d2 > d) {
return `${a}${b}:${c}${d2}`;
}
const min = Math.min(a, b, c, d);
// 2) 분의 십의 자리(c)를 교체 (분은 59 이하)
const c2 = sorted.find(x => x > c && x <= 5);
if (c2 > c) {
return `${a}${b}:${c2}${min}`;
}
// 3) 시의 일의 자리(b)를 교체
const b2 = sorted.find(x => x > b && a * 10 + x <= 24);
if (b2 > b) {
return `${a}${b2}:${min}${min}`;
}
// 4) 시의 십의 자리(a)를 교체 (시는 23 이하)
const a2 = sorted.find(x => x > a && x <= 2);
if (a2 > a) {
return `${a2}${min}:${min}${min}`;
}
// 5) 어떤 자릿수도 증가시킬 수 없는 경우
return `${min}${min}:${min}${min}`
};
console.log(findClosestTime(time));실행 결과
19:39
마무리
이 풀이의 장점은 모든 가능한 시간 조합을 탐색하지 않고도 답을 찾을 수 있다는 것입니다. 자릿수를 뒤에서부터 우선적으로 조정하기 때문에 항상 "가장 가까운 다음 시간"을 보장하며, 시간 복잡도 역시 상수 시간(O(1))으로 매우 효율적입니다. 비슷한 유형의 자릿수 조작 문제를 풀 때도 동일한 접근 방식을 활용할 수 있으니 참고해 보시기 바랍니다.