본문 바로가기
알고리즘

[프로그래머스lv2] 과제 진행하기

by limew 2023. 8. 11.

https://school.programmers.co.kr/learn/courses/30/lessons/176962#

 

 

1번째 풀이

1. plans의 start, playtime 시간문자열을 숫자로 변환한뒤, 그 시간에 따라 sort한다

2. 맨 처음 과제를 stack에 넣고 진행한다

3. 앞의 과제가 끝나는 시간 <= 다음 과제가 시작하는 시간이면 앞의과제는 완료되었고 answer에 과제이름을 넣는다.

4. 앞의 과제가 끝나는 시간 > 다음과제가 시작하는 시간이면, 앞의과제는 remained에 넣는다 (이때 playtime 남은 시간 = 앞 과제하는데 걸리는 시간 - (뒤 과제 시작시간 - 앞 과제시작시간) 으로 계산한다.)

5. 3번의 앞과제가 이미 다 끝났을때 remained남은과제가 남아있고 뒤 과제시작시간이 아직 안 됬을때 remained에서 뒤 과제를 빼서 stack에 넣고 뒤 과제를 마저진행한다.

6. 남은 과제를 하다가 끝나면 3번처럼 answer에 과제이름을 넣고, 미완료하면 다시 남은시간을 계산한뒤 remained에 넣는다.

이렇게 stack에 과제가 있을때까지 순환을 한뒤, 맨 마지막에 남은 remained과제를 뒤에서 하나씩 pop해서 answer에 넣어준다.

 

제출전 테스트케이스는 다 통과했지만

제출 후 케이스는 1,2, 14, 15, 16, 18, 19, 22, 23, 24만 통과하고 나머지는 실패ㅠ

function convertNum(str) {
    return Number(str.split(':').join(''));
}

function convertClock(num) {
    const lastTwo = num % 100;
    if (lastTwo < 60) {
        return num;
    } 
    let division = Math.floor(lastTwo / 60);
    let remain = lastTwo % 60;
    return Math.floor(num / 100)*100 + 100*division + remain;
}

function solution(plans) {
    var answer = [];
    const stack = [];
    const remained = [];
    let nowTime = plans[0][1]; // 맨 처음 시작 시각
    
    // 시간을 숫자로 변환후 시간에 따라 sort
    let sortedPlans = plans.map(p => [p[0], convertNum(p[1]), convertNum(p[2])]).sort((a, b) => a[1] - b[1]);
    // 맨 처음 과제 stack에 넣기
    stack.push(sortedPlans.shift());
    
    // 스케쥴대로 진행
    while(stack.length) {
        const curr = sortedPlans.shift();
        if (!curr) {
            answer.push(stack.shift()[0]);
            break;
        }
        const [prevName, prevStart, prevPlaytime] = stack.shift();
        // 전 과제가 끝날시각
        const prevFinishTime = convertClock(prevStart + prevPlaytime);
        // 완료시
        if (prevFinishTime <= curr[1]) {
            stack.shift();
            answer.push(prevName); // 끝낸과제 올리기
            nowTime += prevPlaytime;
            // remained한게 없음 바로 다음 과제로 넘어간다
            if (!remained.length) {
                stack.push(curr);
                nowTime = curr[1];
            } else {
                // remained한게 있고 
                // 다음 과제까지 시간이 남으면 remained를 진행
                if (nowTime < curr[1]) {
                    const [name, remainedTime] = remained.pop();
                    stack.push([name, nowTime, remainedTime]);
                    sortedPlans.unshift(curr); // 다시 넣기
                } 
                // 다음과제까지 시간이 없으면 바로 다음 과제 진행
                else {
                    stack.push(curr);
                }
            }
        } 
        // 미완료
        else {
            // stack에서 빼서 remained에 넣고, stack에는 그 다음 과제를 넣는다
            stack.pop();
            remained.push([prevName, prevPlaytime - (curr[1] - prevStart)]);
            nowTime = curr[1];
            stack.push(curr);
        }
    }
    // 남은것들 완료
    while (remained.length) {
        answer.push(remained.pop()[0]);
    }
    return answer;
}

 

 

 

2번째 풀이

처음에는 convertClock 함수를 만들어서시간을 60분법으로 변환해줬는데 생각해보니 컴퓨터 입장에선 이렇게 할 필요 없었다.

그냥 split(':')한뒤 split()[0] * 60 + split()[1] 이렇게 timestamp 숫자로 시간비교를 하니 올 통과.

 

function convertNum(str) {
    const [h, m] = str.split(':').map(e => Number(e));
    return h*60 + m;
}

function solution(plans) {
    var answer = [];
    const stack = [];
    const remained = [];
    let nowTime = plans[0][1]; // 맨 처음 시작 시각
    
    // 시간을 숫자로 변환후 시간에 따라 sort
    let sortedPlans = plans.map(p => [p[0], convertNum(p[1]), Number(p[2])]).sort((a, b) => a[1] - b[1]);
    console.log(sortedPlans)
    // 맨 처음 과제 stack에 넣기
    stack.push(sortedPlans.shift());
    
    // 스케쥴대로 진행
    while(stack.length) {
        const curr = sortedPlans.shift();
        if (!curr) {
            answer.push(stack.shift()[0]);
            break;
        }
        const [prevName, prevStart, prevPlaytime] = stack.shift();
        // 전 과제가 끝날시각
        const prevFinishTime = prevStart + prevPlaytime;
        // 완료시
        if (prevFinishTime <= curr[1]) {
            stack.shift();
            answer.push(prevName); // 끝낸과제 올리기
            nowTime += prevPlaytime;
            // remained한게 없음 바로 다음 과제로 넘어간다
            if (!remained.length) {
                stack.push(curr);
                nowTime = curr[1];
            } else {
                // remained한게 있고 
                // 다음 과제까지 시간이 남으면 remained를 진행
                if (nowTime < curr[1]) {
                    const [name, remainedTime] = remained.pop();
                    stack.push([name, nowTime, remainedTime]);
                    sortedPlans.unshift(curr); // 다시 넣기
                } 
                // 다음과제까지 시간이 없으면 바로 다음 과제 진행
                else {
                    stack.push(curr);
                }
            }
        } 
        // 미완료
        else {
            // stack에서 빼서 remained에 넣고, stack에는 그 다음 과제를 넣는다
            stack.pop();
            remained.push([prevName, prevPlaytime - (curr[1] - prevStart)]);
            nowTime = curr[1];
            stack.push(curr);
        }
    }
    // 남은것들 완료
    while (remained.length) {
        answer.push(remained.pop()[0]);
    }
    return answer;
}

 

 

수정

- 가독성을 위해 [0]이런 magic number사용 자제

- 배열말고 obj으로 풀면 가독성향상

- plans: 앞으로 해야할 과제

- stack: 진행중인 과제

function convertNum(str) {
    const [h, m] = str.split(':').map(e => Number(e));
    return h*60 + m;
}

function solution(plans) {
    // 시간을 숫자로 변환후 시간에 따라 sort
    plans = plans.map(([name, start, playtime]) => {
        return {
            name,
            start: convertNum(start),
            playtime: Number(playtime)
        }
    }).sort((a, b) => a.start - b.start);
    var answer = [];
    const stack = [];
    const remained = [];
    let currTime = plans[0].start; // 맨 처음 시작 시각
    
    // 맨 처음 과제 stack에 넣기
    stack.push(plans.shift());
    
    while(true) {
        if (plans.length && stack.length) {
            const currPlan = stack[0];
            const nextPlan = plans[0];
            // 현재과제 이미 완료
            if (currTime + currPlan.playtime <= nextPlan.start) {
                answer.push(stack.shift().name);
                currTime += currPlan.playtime;
            }
            // 현재과제 미완료시 남은시간 다시 계산해서 stack에 넣기
            else {
                currPlan.playtime -= nextPlan.start - currTime;
                currTime = nextPlan.start;
                stack.unshift(plans.shift());
            }
        }
        // 진행중인 과제가 없을때 다음 과제를 진행
        else if (plans.length) {
            const newPlan = plans.shift();
            stack.push(newPlan);
            currTime = newPlan.start; // 시간업뎃
        } else if (stack.length) {
            answer.push(stack.shift().name);          
        } else {
            break;
        }
    }
    return answer;
}