Coding test/programmers

[프로그래머스] Lv.3 디스크 컨트롤러 (자바스크립트)

hello${name} 2022. 6. 30. 19:55

 

*모든 코드는 Javascript로 작성합니다.

*코드는 참고용으로만 봐주세요!

 


문제

 

https://programmers.co.kr/learn/courses/30/lessons/42627

 

코딩테스트 연습 - 디스크 컨트롤러

하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다. 예를

programmers.co.kr

 

 

 

 

해결방법

 

< 특정 시점에 할 수 있는 일들 중 (해당 시점 이전에 요청이 들어온 일), 가장 소요 시간이 짧은 일을 선택한다.>

   그 이유는 결과값 계산식을 세워보면 알 수 있다.

   ➡ a가 요청시간, b가 소요시간, c가 시작시간이라고 한다면 c+b가 종료 시간이다.

   ➡ 따라서 작업 하나 당 요청에서 종료까지 소요된 시간은 c+b-a.

    여기서 a, b는 고정이므로 c를 줄이는게 중요하다.

   ➡ 모든 작업의 c값을 줄이는 방법은 소요시간이 짧은 것부터 빨리빨리 끝내버리는 것!

 

- 가장 소요 시간이 짧은 일을 빠르게 얻기 위해 힙(최소 힙)을 사용한다

- 메인 while loop에서는 매 시간마다 요청이 들어온 일들을 heap에 넣은 후, 할 수 있는 일들 중 소요 시간 짧은 일을 수행한다.

- 수행 후 종료 시간으로 시간 점프.

- loop은 각 일의 시작 시간을 모두 얻을 때까지 돌게끔 한다.

 

 

 

 

 

코드

 

class Heap{ //최소 힙
    constructor(){
        this.heap = [];
    }
    add(x){
        this.heap.push(x);
        var i = this.heap.length - 1;
        while ( i > 0 ){
            var p = Math.floor((i-1)/2);
            if (this.heap[p] > x){
                this.heap[i] = this.heap[p];
                i = p;
            }
            else break;
        }
        this.heap[i] = x;
    }
    getHead(){
        if (this.heap.length == 0) return false;
        return this.heap[0];
    }
    removeHead(){
        if (this.heap.length == 0) return false;
        var head = this.heap[0];
        if (this.heap.length == 1){
            this.heap = [];
            return head;
        }
        var x = this.heap.pop();
        var i = 0;
        while (2*i + 1 < this.heap.length){
            var child_1 = 2*i + 1;
            var child_2 = 2*i + 2;
            if (this.heap[child_2] && this.heap[child_1] > this.heap[child_2]){
                child_1 = child_2;
            }
            if (this.heap[child_1] < x){
                this.heap[i] = this.heap[child_1];
                i = child_1;
            }
            else break;
        }
        this.heap[i] = x;
        return head;
    }
    isEmpty(){
        if (this.heap.length == 0) return true;
        return false;
    }
}
 



function solution(jobs) {
    var heap = new Heap;
 
    var sortedByRT = [...jobs].sort((a, b)=>{ //시작 시간 빠른 순으로 sort
        return a[0]-b[0];
    })
 
    var time = 0;
    var startedTime = []; //각 일의 시작시간 담을 배열
    var check = new Array(jobs.length); //이미 완료한 일 표시하기 위한 배열
    check.fill(0);
   
    while (startedTime.length < jobs.length){
        //할 수 있는 일들 heap에 추가
        for (let i = 0; i < sortedByRT.length; i++){
            if (sortedByRT[i][0] <= time && check[i] == 0){ // 요청시간이 현재 시간보다 빠르고,
                                                                                                         // 아직 완료하지 않았다면 heap에 추가
                heap.add(sortedByRT[i][1]);
                check[i] = 1;
            }
            if (sortedByRT[i][0] > time) break; // 시간 순으로 정렬했으므로 아닌 거 나오면 break
        }
        //비어 있으면 시간++
        if (heap.isEmpty()){
            time++;
            continue;
        }
        //비어 있지 않으면 가장 빨리 끝나는 일 시작
        var nextEnd = heap.removeHead();
        startedTime.push(time);
        time += nextEnd;
    }
 
    //전체 계산식 = 시작 시간 총합(a) + 걸리는 시간 총합(b)- 요청받은 시간(c) 총합  평균내기.
    var b = 0, c = 0;
    sortedByRT.forEach(([x, y])=>{
        c+=x;
        b+=y;
    })
    var a = startedTime.reduce((x, y)=>x+y);
    var answer = Math.floor((a+b-c)/jobs.length);
   
    return answer;
}