개발하는SM

[프로그래머스] 디스크 컨트롤러 본문

Algorithm/Heap

[프로그래머스] 디스크 컨트롤러

개발하는SM 2021. 2. 12. 16:44

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

 

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

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

programmers.co.kr

문제 설명

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

예를들어

- 0ms 시점에 3ms가 소요되는 A작업 요청 - 1ms 시점에 9ms가 소요되는 B작업 요청 - 2ms 시점에 6ms가 소요되는 C작업 요청

와 같은 요청이 들어왔습니다. 이를 그림으로 표현하면 아래와 같습니다.

한 번에 하나의 요청만을 수행할 수 있기 때문에 각각의 작업을 요청받은 순서대로 처리하면 다음과 같이 처리 됩니다.

- A: 3ms 시점에 작업 완료 (요청에서 종료까지 : 3ms) - B: 1ms부터 대기하다가, 3ms 시점에 작업을 시작해서 12ms 시점에 작업 완료(요청에서 종료까지 : 11ms) - C: 2ms부터 대기하다가, 12ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 16ms)

이 때 각 작업의 요청부터 종료까지 걸린 시간의 평균은 10ms(= (3 + 11 + 16) / 3)가 됩니다.

하지만 A → C → B 순서대로 처리하면

- A: 3ms 시점에 작업 완료(요청에서 종료까지 : 3ms) - C: 2ms부터 대기하다가, 3ms 시점에 작업을 시작해서 9ms 시점에 작업 완료(요청에서 종료까지 : 7ms) - B: 1ms부터 대기하다가, 9ms 시점에 작업을 시작해서 18ms 시점에 작업 완료(요청에서 종료까지 : 17ms)

이렇게 A → C → B의 순서로 처리하면 각 작업의 요청부터 종료까지 걸린 시간의 평균은 9ms(= (3 + 7 + 17) / 3)가 됩니다.

각 작업에 대해 [작업이 요청되는 시점, 작업의 소요시간]을 담은 2차원 배열 jobs가 매개변수로 주어질 때, 작업의 요청부터 종료까지 걸린 시간의 평균을 가장 줄이는 방법으로 처리하면 평균이 얼마가 되는지 return 하도록 solution 함수를 작성해주세요. (단, 소수점 이하의 수는 버립니다)

풀이

먼저, 처리 대상이 되는 Job 들의 배열을 요청 시간 순서대로 정렬해야 한다.

 + 처리된 작업은 중복 처리되어서는 안됨

-> 우선순위 큐를 사용해서 처리해야 하는 Job 들을 시간 순서대로 정렬하고, 처리된 Job 들은 poll 하여 삭제처리 할 수 있도록 구현한다. (waitingJobs 변수)

 

현재 시점을 나타내는 변수 cur 을 두고, 현재 시점에 처리가능한 Job들( Job 의 요청시간이 현재시간보다 이전인 경우)에 대해 작업 우선순위를 정해줄 또 다른 우선순위 큐를 생성한다. (pq 변수)

작업 우선순위

 - 소요시간이 적은 Job 의 우선순위가 높음

 - 소요시간이 같을 경우 요청시간이 빠른 Job 의 우선순위가 높음

 

작업이 모두 종료되는 시점은, 

두 개의 우선순위 큐( waitingJobs, pq )에 대기중인 Job 이 하나도 없을 때 이다.

 

작업 시 유의해야 할 것은,

1. 현재 시점은 하나의 작업을 처리 할 때마다 변경되므로, 하나의 작업씩 처리하면서 현재 처리할 수 있는 작업들의 우선순위를 다시 계산해야 한다.

2. 하나의 작업을 종료한 이후, ( 현재시간 < 대기중인 작업 중 요청시간이 가장 빠른 작업의 요청시간 ) 일 경우에 대한 예외처리가 필요하다.

import java.util.*;

/*
Disk Controller
1. 현재 시점(cur)에 수행할 수 있는 작업 중, 가장 소요시간이 짧은 건부터 처리한다.
2. 각 시점마다 Heap 을 이용하여 소요시간이 가장 짧은 작업을 Poll 한다.
*/

class Solution {
    
    public static class Job{
        int req;
        int takes;
        
        public Job(int req, int takes){
            this.req = req;
            this.takes = takes;
        }
    }
    
    public int solution(int[][] jobs) {
        int answer = 0;
      
        int cur = 0;
        
        // 우선순위 큐
        // 소요시간이 적은 job 의 우선순위가 높음
        // 소요시간이 같아면 요청시간이 빠른 job 의 우선순위가 높음
        PriorityQueue<Job> pq = new PriorityQueue<>((a,b) -> {
            int comparison = a.takes - b.takes;
            return comparison == 0 ? a.req - b.req : comparison;
        });
        
        // 남은 job 들의 list를 담을 큐
        // 작업이 완료된 job 은 삭제되어야 하므로 queue 형태로 구현함.
        PriorityQueue<Job> waitingJobs = new PriorityQueue<>((a,b) -> a.req - b.req);
        
        for(int i=0; i<jobs.length; i++){
            waitingJobs.offer(new Job(jobs[i][0], jobs[i][1]));
        }
        
        // 종료되는 시점 = waiting 중인 Job 이 없고, pq 에도 값이 없을 때
        cur = waitingJobs.peek().req;
        
        while(!waitingJobs.isEmpty() || !pq.isEmpty()){
            
            // 현재 대기중인 작업 중 요청시간이 가장 빠른 작업의 요청시간이 현재 시간보다 클 경우
            if(pq.isEmpty() && !waitingJobs.isEmpty() && waitingJobs.peek().req > cur){
                cur = waitingJobs.peek().req;
            }
            
            // 대기중인 작업들 중 현재시간보다 요청시간이 작거나 같은 작업을 모두 대상으로 잡음
            while(!waitingJobs.isEmpty() && waitingJobs.peek().req <= cur){
                pq.offer(waitingJobs.poll());
            }
            
            // 디스크 스케줄링 작업 대상이 있을 경우, 우선순위에 따라 한 건씩 처리한다.
            if(!pq.isEmpty()){
                Job front = pq.poll();
                cur += front.takes;
                answer += (cur - front.req);    
            }
        }
        
        
        return answer / jobs.length;
    }
}

 

'Algorithm > Heap' 카테고리의 다른 글

Heap 과 우선순위 큐(Priority Queue)  (0) 2021.02.12
[프로그래머스] 이중우선순위큐  (0) 2021.02.12
[프로그래머스] 더 맵게  (0) 2021.02.12