⭐ intro : 문제를 생각해나간 방식
피도 눈물도 없는 사악한 민식이를 혼쭐내주러 가는 영식이의 장렬한 스토리다. 코딩으로 어떻게 풀어야할까? 이번에도 마찬가지로 두 조건을 순회하면서 값을 비교하는 형식으로 코드를 만들어갔다. 코드문을 이해하고, 육안으로 테스트케이스까지 출력되게끔 만드는데는 오래 걸리지 않았는데 자꾸 틀렸다고 나와서, 도데체 무엇이 문제인지 오류를 찾는 부분에서 시간을 상당히 소요하게 되었다. 이번 문제의 오류 포인트는 infinity였다....
버스 출발시간과 맞지 않으면 -1을 내뱉는 케이스에서, 결과값은 예상대로 잘 뱉는데 문제가 뭐지? 싶다가 해당 케이스에서 내 알고리즘 상에서 이 Infinity가 들어가는 부분을 발견하고야 만것이다. 이 케이스를 발견하는데까지 수많은 삽질이 있었다.
재밌는(안재밋어? 웃어...) tmi로... 여기서 나의 N적 쓸모없는 상상이 문제를 더 크게 만들뻔했는데, 아 시간이라니까 1분부터 60분까지, s와 ms로 계산해서 60분이 지나가면 다시 1분으로 순회해서 24시간을 만들어야지 하는 진짜 하등 필요없는 현실적인 고민으로 넘어갈뻔...;; 시분초가 아닌 그냥 하나의 일종의 '시간'이라는 이 문제만의 단위개념으로 생각해야 했다. 또 버스가 한바퀴 순회하면 다시 또 교대근무 하니까 새로운 기사님이 모는 2회차 버스 돌려지는것 까지 생각....어우 생각만해도 너무 쓸데없이 생각이 많았다. 생각해보니 과거의 나는 이런 쓸모없는 문제 대입 방식때문에 공부를 제대로 하지 못했었던것 같다. 이성적으로 봐야하는것을 필요없이 감정적으로 보고있었던 나... 지금도 종종 이러고있다.
⭐ 풀이과정
요전과 같이 항상 주어진 케이스를 잘게 쪼개기부터 시작했다. 크게 영식이랑 관련된 값들(ysic)과 버스관련 값(bus)으로 나뉘었고, 버스는 버스대수가 1대이상이 들어올것을 감안하여 전개연산자로 전부 묶어주었다. 또한 ysic에서 현재 버스 갯수가 몇개인지는 크게 사용되지 않을것 같아 첫번째값은 하이픈으로 제외하고 중요한 영식이가 도착한 시간 T값만 살려두었다. 즉 함수의 매개변수에는 T와 bus 배열만 들어가게 된다.
또한 매개변수 값들이 string으로 들어와있는데 계속 숫자계산을 하게될것으로 예상하여 number 타입으로 변경해서 숫자값들로 변경된 조건들과 임의의 결과값들이 들어갈 arr 배열을 만들어 두었다. 처음에는 Set()을 이용하여 중복값을 제거할까 싶었는데 어자피 최소시간만 계산해서 뱉으므로 굳이 Set까지는 안만들어도 될듯하고 일반적인 Array를 하나 만들어 두었다. 그리고 각각 S I C를 문제에서 제시하고 있어서 해당 단어값들로 구성된 변수들을 bus 배열에서 분리해서 할당해주었다.
const [ysic, ...bus] = input;
const [_, T] = ysic.map(Number);
function solution(T, bus) {
let arr = [];
for (let [S, I, C] of bus) {
const start = Number(S);
const Interval = Number(I);
const count = Number(C);
}
다음으로 현 bus배열을 반복문 시작한 반복문에서 해당 요소를 기준으로 다시 비교해서 반복하는 이중반복문을 만들어준다. 내부 변수에 실시간으로 더해지는 버스 기준 도착시간 (시작시간 + (간격시간 * 버스 댓수만큼의 횟수)) sum을 만들고 이 sum이 영식이가 도착하는 T 시간보다 크거나 같아질때 해당 시간의 차이값만큼을 arr에 담고 반복문을 끊어버리도록 만들었다.
예를들어 영식이가 285'분'에 도착하고 버스가 150분에 출발하는 시간하고 50분 간격으로 10대가 있으면 버스는 150, 200, 250....분에 출발하고 총 10대가 출발해서 마지막 버스는 600분에 출발하게 된다. 여기서 영식이가 도착하는 가장 근접하는 시간은 바로 300분, 무조건 영식이의 도착 시간보다 같거나 커야하는 바로 '그 순간'을 캐치해야 한다. 250에서 300으로 값이 할당되는 그 순간을 잡고, 영식이의 도착시간인 T값을 빼서 arr값에 넣어야 했다.
그러나 여기에서 나의 중대한 실수가 발생했었다. 바로 포스팅 중간에 앞서 말했었던 Infinity 시간 관련 이슈가 있었다. 바로 버스의 마지막 시간이 영원히 계속 영식이의 도착하는 시간 이전에 도착해서 떠나버리는, 버스와 영식이가 영원히 평행세계속에 갖혀버리는 참극(!!!)을 내가 만들어버리고 만 것.... 영식이가 도착하는 시간T와 동시에 도착하는 버스가 아닌이상 보편적인 반복문의 흐름은 영식이가 도착하는 시간 T보다 무조건 작다. 그래서 해당 부분을 추가하여 해당 조건이면 바로 다음 else로 넘어가도록 해서 해당없으면 아무것도 하지 않고 담백하게 끝내도록 만들었다.
if (T > lastTime) {
continue;
}
이 부분을 처리하지 않으면 결과값이 -1로 나오는 영식이와 버스와의 평행선 부분은 무한대로 계속 뻗어나가게 된다...
해당 코드가 잘 실행되면 arr에는 영식이의 도착시간과 비교해서 가장 빨리 캠프로 갈 수 있는 시간이 버스별로 담가져 있다. 그래서 서 현재 차이값만큼의 시간이 담긴 배열에서 Math.min 메서드를 이용해서 최소값을 뽑아주되, arr의 값의 '존재'할 경우인 length가 0 초과일경우에 해당 최소값을 넘겨주도록 하고, 영식이 도착시간에 버스가 이미 순회를 끝내버려서 배열값에 아무것도 없는 경우인 경우엔 -1을 리턴하도록 해당 조건문을 만들어 주었다.
if (arr.length > 0) {
const result = Math.min(...arr);
return result;
} else {
return -1;
}
⭐ 제출답안
const [ysic, ...bus] = input;
const [_, T] = ysic.map(Number);
function solution(T, bus) {
let arr = [];
for (let [S, I, C] of bus) {
const start = Number(S);
const Interval = Number(I);
const count = Number(C);
for (let j = 0; j < count; j++) {
let sum = start + Interval * j;
let lastTime = start + Interval * (count - 1);
if (T > lastTime) {
continue;
} else if (sum >= T) {
arr.push(sum - T);
break;
}
}
}
if (arr.length > 0) {
const result = Math.min(...arr);
return result;
} else {
return -1;
}
}
console.log(solution(T, bus));
⭐ 공부했던 개념들
이 문제를 위해서 특별히 더 공부한 부분은 없다. 계속 코드를 들여다보고 무한 console.log를 찍으면서 범인코드를 색출해내기의 반복...
문제를 계속 풀수록 리트코드라는 외국 웹사이트가 정말 선녀같다는 느낌이 들었다. 존댓말쓰는 친구와의 대화 캡쳐를 통해 내 의견을 정리하고 마무리 하겠다.