[CDT - Javascript] 프로그래머스 연습문제 @ 과제 진행하기

김현수·2023년 12월 24일
0

cdt

목록 보기
36/51
post-thumbnail

🖋️ 과제 진행하기


# 문제 설명

과제를 받은 루는 다음과 같은 순서대로
과제를 하려고 계획을 세우기

  • 조건

    • 과제는 시작하기로 한 시각이 되면 시작

    • 새로운 과제를 시작할 시각이 되었을 때, 기존에 진행 중이던 과제가 있다면
      진행 중이던 과제를 멈추고 새로운 과제를 시작

    • 진행중이던 과제를 끝냈을 때, 잠시 멈춘 과제가 있다면,
      멈춰둔 과제를 이어서 진행

      • 만약, 과제를 끝낸 시각에 새로 시작해야 되는 과제와
        잠시 멈춰둔 과제가 모두 있다면, 새로 시작해야 하는 과제부터 진행
    • 멈춰둔 과제가 여러 개일 경우, 가장 최근에 멈춘 과제부터 시작

  • 매개 변수

    • 과제 계획을 담은 이차원 문자열 배열 plans
  • 반환값

    • 과제를 끝낸 순서대로 이름을 배열에 담아 return

  • 📢 제한사항

    • 3 ≤ plans의 길이 ≤ 1,000

      • plans의 원소는 [name, start, playtime]의 구조
        • name : 과제의 이름을 의미
          • 2 ≤ name의 길이 ≤ 10
          • name은 알파벳 소문자로만 이루어 짐
          • name이 중복되는 원소 x

        • start : 과제의 시작 시각
          • "hh:mm"의 형태로 "00:00" ~ "23:59" 사이의 시간값
          • 모든 과제의 시작 시각은 달라서 겹칠 일 x
          • 과제는 "00:00" ... "23:59" 순으로 시작
            즉, 시와 분의 값이 작을수록 더 빨리 시작한 과제

        • playtime : 과제를 마치는데 걸리는 시간을 의미, 단위는 분
          • 1 ≤ playtime ≤ 100
          • playtime은 0으로 시작 x

        • 배열은 시간순으로 정렬된 상태 x

    • 진행중이던 과제가 끝나는 시각과
      새로운 과제를 시작해야하는 시각이 같은 경우
      진행중이던 과제는 끝난 것으로 판단


  • 📰 입출력 예시

plansresult
[["korean", "11:40", "30"], ["english", "12:10", "20"], ["math", "12:30", "40"]]["korean", "english", "math"]
[["science", "12:40", "50"], ["music", "12:20", "40"], ["history", "14:00", "30"], ["computer", "12:30", "100"]]["science", "history", "computer", "music"]
[["aaa", "12:00", "20"], ["bbb", "12:10", "30"], ["ccc", "12:40", "10"]]["bbb", "ccc", "aaa"]



  • CODE

function solution(plans) {
    
    // start 시간으로 정렬
    // onePlan : [name, start, playtime]
    plans.sort(([_na, startA, _pa], [_nb, startB, _pb]) => {
        const _startA = +startA.replace(":","");
        const _startB = +startB.replace(":","");
        
        return _startA - _startB;
    })

    // 끝내는 시간
    const playTime = (start, playTime) => {
        const times = start.split(":").map((v) => +v);
        const mm = times[1] + +playTime;
        
        if (mm >= 60) {
            const hh = ~~(mm / 60);
            return `${times[0] + hh}:${mm - hh * 60}`
        }
        return `${times[0]}:${mm}`
    }

    // 사이 시간 (단위: 분)
    const diffTime = (time1, time2) => {
        const times_a = time1.split(":").map((v) => +v);
        const times_b = time2.split(":").map((v) => +v);
        
        const hh = times_b[0] - times_a[0];
        const mm = times_b[1] - times_a[1];
        
        return hh * 60 + mm;
    }

    const answer = [];

    let stack = [];
    let time = plans[0][1];
    while (plans.length) {
        const [name, start, playTime] = plans.shift();

        // 멈춰둔 과제 있을 때
        if (stack.length) {
            let diff = diffTime(time, start);
            while (stack.length && diff > 0) {
                if (time == start) break;
                const [stoppedName, lastTime] = stack.pop();
                
                diff -= lastTime;
                if (diff < 0) {
                    stack.push([stoppedName, Math.abs(diff)]);
                } else {
                    answer.push(stoppedName);
                }
            }
        } 
        
        if (plans.length) {
            const [_n, nextStart, _p] = plans[0];
            const end = playTime(start, playTime);
            if (timeDiff(end, nextStart) < 0) {
                const diff = diffTime(start, nextStart);
                stack.push([name, playTime - diff]);
            } else {
                answer.push(name)
            }
            time = end;
        } else {
            answer.push(name)
        }
        
    }
    
    if (stack.length) {
        stack.reverse().forEach(([name, _]) => answer.push(name));
    }
    
    return answer;
}

풀이

  • 경우의 수를 구하여 조건에 맞춰 solution 구하기

  • 변수 정의
    • playTime : 끝내는 시간을 반환하는 function
    • diffTime : 시간과 시간 사이의 차이를 반환하는 function
    • stack : 멈춘 과제를 담아두는 대기열
    • time : 작업하는 현재 시간

  • plans 를 start 시간을 정렬

  • 새로운 과제 있을 때 반복문
    • time 과 start 시간 사이에 간격이 있을 때
      • 멈춘 과제 있을 때
        • diff 시간 차이 반환
        • 시간 간격이 0 이나 멈춘 과제 없어질 때까지 반복문
          • start 시간 될때까지 멈춰둔 과제 진행
          • diff 와 lastTime 비교후 stack 갱신
      • 멈춘 과제 없을 때 (다음 스케줄 진행)
        • 다음 새로운 과제가 있을 때
          • start 에서 playTime 적용한 시간 end 반환
          • nextStart 와 비교
            • 초과 : stack 에 push
            • 완료 : answer 에 push
        • 다음 새로운 과제가 없을 때
          • 완료 : answer 에 push

  • 멈춰둔 과제 최신순으로 answer 에 push
profile
일단 한다

0개의 댓글