CS/Algorism

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

olsohee 2024. 3. 7. 14:02

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

모든 작업들의 평균 작업시간을 작게 만들어야 하는 문제이다. 운영체제에서 CPU 스케줄링에서 배운 최단작업 우선 스케줄링 기법(SJF)이 생각났는데, 그대로 하면 된다! 아이디어를 떠올리는 건 괜찮았는데, 구현이 어려웠고 자꾸 8번과 18번 테스트 케이스에서 실패해서 고생한 문제이다. 주요 포인트는 다음과 같다.

  • 현재 시간까지 들어온 작업들을 큐에 넣는다. 그런데 이때 매개변수로 주어지는 jobs는 요청시간이 빠른 순서대로 정렬되어 있지 않다. 따라서 이를 que1에 넣고, que1을 요청시간을 기준으로 오름차순 해주었다.
  • 이제 현재 시간까지 들어온 작업들을 que1에서 que2로 옮기면 된다.
  • 그리고 que2는 소요시간을 기준으로 오름차순 해주었고, que2에 있는 작업들 중 소요시간이 가장 적은 작업을 우선으로 수행하면 된다.

위 로직대로 구현만 잘..! 하면 된다. 그런데 주의할 점은 내 코드에서 첫 번째 작업을 먼저 수행하고 그 뒤부터 while문을 타게 되는데, 만약 요청시간이 15, 소요시간이 34인 [15, 34]작업과 요청시간이 15, 소요시간이 2인 [15, 2]작업이 들어왔을 때, [15, 34]인 작업을 첫 번째 작업으로 취급하게 된다면, 현재 시간인 now 변수가 49(15+34)가 된다. 그리고 나서 while문을 타게 되면서 원하는대로 결과가 나오지 않는다. 따라서 que1에서 요청시간을 기준으로 오름차순을 정렬할 때, 요청시간이 같다면 소요시간을 기준으로도 오름차순 정렬을 해줘야 한다.

 

이에 대한 테스트 케이스는 다음과 같다. 

  • jobs: [[24, 10], [28, 39], [43, 20], [37, 5], [47, 22], [20, 47], [15, 34], [15, 2], [35, 43], [26, 1]]
  • return: 72

내가 생각한 로직에서 예외 상황을 찾는 것이 참 어렵다.. 정렬을 했을 때 "만약 정렬 기준이 같다면? 같으면 또 다른 기준으로 정렬을 해줘야하지 않는지?"를 고려해보자.

import java.util.*;

class Solution {
    public int solution(int[][] jobs) {
        
        // que1: 요청순서를 기준으로 오름차순
        Queue<Job> que1 = new PriorityQueue(new Comparator<Job>() {
            @Override
            public int compare(Job o1, Job o2) {
                // 주의!!! 요청시간이 같으면, 소요시간이 짧은 것이 먼저 처리되도록
                if (o1.start == o2.start) {
                    return o1.time - o2.time;
                }
                return o1.start - o2.start;
            }
        });
        
        for (int[] job : jobs) {
            que1.add(new Job(job[0], job[1]));
        }
        
        // que2: 소요시간을 기준으로 오름차순
        Queue<Job> que2 = new PriorityQueue(new Comparator<Job>() {
            @Override
            public int compare(Job o1, Job o2) {
                // 소요시간이 같으면, 먼저 요청된 것이 먼저 처리되도록
                if (o1.time == o2.time) {
                    return o1.start - o2.start;
                }
                return o1.time - o2.time;
            }
        });
        
        // 첫 번째 작업 수행
        Job poll = que1.poll();
        int now = poll.start + poll.time;
        int sum = now - poll.start;
        
        while (!que1.isEmpty() || !que2.isEmpty()) {
            
            // 현재 시간까지 들어온 요청을 que에 넣기
            while (!que1.isEmpty()) {
                if (now < que1.peek().start) {
                    break;
                } 
                que2.add(que1.poll());
            }
            
            // 만약 요청이 안들어왔으면, 다음 요청까지 시간 보내기
            if (que2.isEmpty()) { 
                now = que1.peek().start;
                continue; // continue를 해서 바뀐 현재 시간을 기준으로 다시 que1의 작업들을 que2로 넣어줘야 함
            }
        
            // que2에 있는 작업들 중 소요시간이 가장 작은 작업 수행하기
            Job job = que2.poll();
            now += job.time;
            sum += now - job.start;
        }
        return sum / jobs.length;
        
    }
    
    class Job {
        int start;
        int time;
        public Job (int start, int time) {
            this.start = start;
            this.time = time;
        }
    }
}

'CS > Algorism' 카테고리의 다른 글

[백준] 2146. 다리 만들기  (0) 2024.04.10
소수인지 판단할 때 시간 복잡도 줄이기  (0) 2024.03.21
[프로그래머스] 여행경로  (0) 2024.03.06
[백준] 1082. 방 번호  (1) 2024.03.05
[백준] 1034. 램프  (1) 2024.03.05