이번 문제는 답지를 보고 풀었다.
나혼자 해보려고 했으나 내가 모르는 부분들도 있었고
반복문의 조건식에서 어떤 조건식을 달지 몰라서 해답을 찾게 되었다.
그래도 내가 생각했던 방식이 맞긴 맞았다.
일단 문제부터 보자.
하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다.
예를들어
- 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 함수를 작성해주세요. (단, 소수점 이하의 수는 버립니다)
제한 사항
- jobs의 길이는 1 이상 500 이하입니다.
- jobs의 각 행은 하나의 작업에 대한 [작업이 요청되는 시점, 작업의 소요시간] 입니다.
- 각 작업에 대해 작업이 요청되는 시간은 0 이상 1,000 이하입니다.
- 각 작업에 대해 작업의 소요시간은 1 이상 1,000 이하입니다.
- 하드디스크가 작업을 수행하고 있지 않을 때에는 먼저 요청이 들어온 작업부터 처리합니다.
입출력 예
jobs | return |
[[0, 3], [1, 9], [2, 6]] | 9 |
입출력 예 설명
문제에 주어진 예와 같습니다.
- 0ms 시점에 3ms 걸리는 작업 요청이 들어옵니다.
- 1ms 시점에 9ms 걸리는 작업 요청이 들어옵니다.
- 2ms 시점에 6ms 걸리는 작업 요청이 들어옵니다.
위 문제에서 내가 생각한 방식은 아래와 같다.
1. 처음 들어가는것은 요청순서가 제일 빠른순부터 넣자.
2. 그 다음부턴 요청시간이 현재 작업시간보다 작은애중 작업량이 작은 순부터 작업을 하자.
나는 이렇게 생각을 하고 문제에 접근을 하였으나 <>부분에 배열이 들어갈수 있는지 몰랐고
그 배열들을 정렬이 가능한지도 몰라 답지를 보았다.
소스를 봐보자.
public int solution(int[][] jobs) {
int answer = 0;
int len = jobs.length;
int index = 0;
int time = 0; //작업의 현재 시간을 측정할 변수가 필요함, 시작은 0초
//우선순위 int[]을 받는데 정렬은 [][1]의 자리를 오름차순으로 해서 정렬한다.
//그렇게 되면 작업량이 적은 순으로 뽑아 올수 있음
PriorityQueue<int []> pq = new PriorityQueue<>((o1,o2) -> (o1[1] - o2[1]));
//jobs를 정렬할건데 어떻게 정렬할거냐 배열 안에 [0][]의 자리를 오름차순으로 정렬한다.
//요청 속도가 빠른 순으로 배열이 정렬되어 있다.
Arrays.sort(jobs,(o1,o2) -> (o1[0] - o2[0]));
//index를 늘려서 jobs[0][]부터 접근하기위해서도 있고
//비어 있지 않다면 아래의 작업을 다시 해야하기 때문에 비어있지 않을때 진입이가능해야함
while(index < len ||!pq.isEmpty()) {
//index가 길이보다 작고 요청시간이 현재 시간보다 작거나 같을때 진입
while(index<len && jobs[index][0] <= time) {
//현재 시간보다 작은애 넣고 index 1 증가 시킴으로써 다음걸로 감
pq.offer(jobs[index++]);
}
//요청시간이 0초인애가 없거나 요청시간이 작업시간이 요청시간보다 클때 그냥 time을 넣음(pq에 담기 위해서)
//그냥 time을 넣어도 오류가 나지 않는 이유가 어처피 작업시간보다 크기 때문에
//time을 해당작업의 대기시간으로 바꿔줘도 무방함
if(pq.isEmpty()) {
time = jobs[index][0];
}else {
int[] job = pq.poll();
//대기 시간과 작업량을 더함
answer += time - job[0] + job[1];
//작업을 하나 마쳤으니 현재시간을 변경
time += job[1];
}
}
return answer/len;
}
내가 자세한 내용들은 위 소스에 주석을 달아놨으니 확인하면 될것 같다.
나는 위 소스를 보고 첨에 이해가 안갔지만 디버깅을 해보면서 하니 빠르게 이해가 갔다.
(손코딩도 좋지만 헷갈리고 오래걸림....)
디버깅을 하는 방법에 대해서는 아래 링크를 걸어둘테니 확인해보면 될것 같다.
https://wpioneer.tistory.com/92
느낀점
1. PriorityQueue의 <>(제네릭)안에는 비교가 될만한 기준을 ()안에 정해 놓으면 정렬이 된 상태로 저장이 된다.
2. 반복문의 조건식에는 내가 글로 어떨때 조건을 비교할지 적어 놓은걸 넣어보자.
3. 모든 테스트 케이스를 생각해보고 문제를 풀자.
ex)
if(pq.isEmpty()) {
time = jobs[index][0];
}
위부분 처럼 요청시간이 작업시간을 벗어났다던가 했을때의 경우
'코딩일기 > 알고리즘' 카테고리의 다른 글
[프로그래머스 : 레벨1] K번째 수 : 선택정렬(Java) (0) | 2021.06.02 |
---|---|
[프로그래머스 : 레벨 3] 이중 우선순위 큐 : PriorityQueue (Java) (0) | 2021.05.30 |
[프로그래머스 : 레벨 2] 더 맵게 (feat. PriorityQueue , Java) (0) | 2021.05.28 |
[자료구조] 힙(Heap) 이란 (0) | 2021.05.27 |
[프로그래머스 : 레벨2] 주식가격 (Java) (0) | 2021.05.27 |