
문제
문제 설명
하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다.
예를들어
- 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 걸리는 작업 요청이 들어옵니다.
아이디어
이전에 풀었던 백준의 heap 문제를 활용해서 heap 자료구조를 사용해서 풀 생각을 가지고있었다.
처음에 들었던 생각은, jobs에 들어오는 배열들이 0, 1, 2... 이런식으로 들어오니까, 그 값을 인덱스로 사용하고, 1번 인덱스에 있는 값을 넣어주면, 들어오는 시간에 대해서도 정렬이 되니까, 정답일 줄 알았다.
하지만, 0초에 다른 작업 시간을 가지는 job도 존재할 수 있기때문에, 위의 생각은 틀렸던 것 같다.
그렇다고 한 문제 풀자고 배열로 heap을 구현하는 것도 너무 힘들기때문에 찾아본 결과, PirorityQueue라는 게 존재했다.
PriorityQueue란?
PriorityQueue란 우선순위 큐라는 뜻으로, 일반적인 큐를 사용하는 것처럼 사용하되, args로 lambda 함수를 넣어서, comparable하게 만들어줘야 사용이 가능하다.
int[][] arr = {{0,3},{1,9},{2,6}}
PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2) -> o1[1] - o1[2]);
위의 arr는 프로그래머스 문제에 있는 예시 입력이다.
그리고 다음과 같이 pq를 선언하면, 1번 인덱스의 값을 기준으로 오름차순으로 정렬된다.
arr를 0번 인덱스 기준으로 정렬한 array 하나와, 1번 인덱스 기준으로 정렬한 PriorityQueue가 있으면 문제를 풀 수 있을 것 같다.
반복문을 한 번 돌 때마다 증가하는 time 변수와, 현재 진행중인 job index를 가르킬 job_idx, 일이 끝난 시간을 더하기 위한 end를 사용한다. cnt로 jobs를 전부 순회하면서 계산했는지 확인한다면, 평균을 구할 수 있을 것같다.
일단, 비어 있는 상태에서 시작하고, 현재 job_idx가 배열의 마지막 배열까지 가르키면서, 현재 job idx가 가리키고 있는 job의 수행시간이 end보다 작거나 같을 때, pq에 더해준다. 그 후에, job idx를 1만큼 더해서 다음에 들어오면 다음 job을 가르키도록 한다.
여기서는 특정 초에 들어온 작업들을 모두 넣어준다. 예를 들면, 0초에 3개의 작업이 들어온다면 해당 작업들을 작업 소요 시간 기준으로 오름차순하여 pq에 적재한다.
pq가 비어있다면, 특정 초에 들어온 모든 일들이 끝난 것이므로, 그 다음 초를 가리키도록 end를 설정한다.
그렇지 않다면, pq에서 최상단 노드를 poll하여, 해당 값을 answer에 더해준다.
이때, 프로그래머스 페이지에 나와있는 그림들을 참고하여, 대입식을 짜서 answer에 더해준다.
이러한 과정들을 job idx가 마지막까지 가르키게 하여, 걸리는 총 시간 answer를 배열의 길이만큼 나눠 평균을 구해준다.
소스코드
import java.util.*;
class Solution {
public int solution(int[][] jobs) {
int answer = 0;
int cnt = 0;
int job_idx = 0;
int end = 0;
Arrays.sort(jobs,(o1,o2) -> o1[0] - o2[0]);
PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2) -> o1[1] - o2[1]);
int time = 0;
while(cnt < jobs.length){
while(job_idx < jobs.length && jobs[job_idx][0] <= end){
pq.add(jobs[job_idx]);
job_idx++;
}
if(pq.isEmpty()){
end = jobs[job_idx][0];
}
else{
int[] temp = pq.poll();
answer += temp[1] + end - temp[0];
end += temp[1];
cnt++;
}
}
return (int)Math.floor(answer / jobs.length);
}
}
결과
채점결과
정확성: 100.0
합계: 100.0 / 100.0
후기
처음에 순수 heap으로 하려다가 머리가 아파 포기하고 구글 서칭을 했었던 것같은데, 그렇게 하기를 잘 한 것같다.
결국 주어진 시간내에 문제를 풀어야하니까, 어떤 상황에서 어떤 자료구조를 사용해야 하는 지 아는 게 더 중요한 것같다.
'코딩 테스트' 카테고리의 다른 글
[백준 골드5] 12865번 평범한 배낭 / Java (0) | 2024.05.06 |
---|---|
[백준 골드3] 2830번 행성 X3 / Java (0) | 2024.04.23 |
[백준 실버5] 24174 알고리즘 수업 - 힙 정렬2 / Java (0) | 2024.04.21 |
[백준 실버4] 요세푸스 문제 / Java (1) | 2024.04.19 |
[프로그래머스 level2] 프로세스 / Java (0) | 2024.04.19 |

문제
문제 설명
하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다.
예를들어
- 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 걸리는 작업 요청이 들어옵니다.
아이디어
이전에 풀었던 백준의 heap 문제를 활용해서 heap 자료구조를 사용해서 풀 생각을 가지고있었다.
처음에 들었던 생각은, jobs에 들어오는 배열들이 0, 1, 2... 이런식으로 들어오니까, 그 값을 인덱스로 사용하고, 1번 인덱스에 있는 값을 넣어주면, 들어오는 시간에 대해서도 정렬이 되니까, 정답일 줄 알았다.
하지만, 0초에 다른 작업 시간을 가지는 job도 존재할 수 있기때문에, 위의 생각은 틀렸던 것 같다.
그렇다고 한 문제 풀자고 배열로 heap을 구현하는 것도 너무 힘들기때문에 찾아본 결과, PirorityQueue라는 게 존재했다.
PriorityQueue란?
PriorityQueue란 우선순위 큐라는 뜻으로, 일반적인 큐를 사용하는 것처럼 사용하되, args로 lambda 함수를 넣어서, comparable하게 만들어줘야 사용이 가능하다.
int[][] arr = {{0,3},{1,9},{2,6}}
PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2) -> o1[1] - o1[2]);
위의 arr는 프로그래머스 문제에 있는 예시 입력이다.
그리고 다음과 같이 pq를 선언하면, 1번 인덱스의 값을 기준으로 오름차순으로 정렬된다.
arr를 0번 인덱스 기준으로 정렬한 array 하나와, 1번 인덱스 기준으로 정렬한 PriorityQueue가 있으면 문제를 풀 수 있을 것 같다.
반복문을 한 번 돌 때마다 증가하는 time 변수와, 현재 진행중인 job index를 가르킬 job_idx, 일이 끝난 시간을 더하기 위한 end를 사용한다. cnt로 jobs를 전부 순회하면서 계산했는지 확인한다면, 평균을 구할 수 있을 것같다.
일단, 비어 있는 상태에서 시작하고, 현재 job_idx가 배열의 마지막 배열까지 가르키면서, 현재 job idx가 가리키고 있는 job의 수행시간이 end보다 작거나 같을 때, pq에 더해준다. 그 후에, job idx를 1만큼 더해서 다음에 들어오면 다음 job을 가르키도록 한다.
여기서는 특정 초에 들어온 작업들을 모두 넣어준다. 예를 들면, 0초에 3개의 작업이 들어온다면 해당 작업들을 작업 소요 시간 기준으로 오름차순하여 pq에 적재한다.
pq가 비어있다면, 특정 초에 들어온 모든 일들이 끝난 것이므로, 그 다음 초를 가리키도록 end를 설정한다.
그렇지 않다면, pq에서 최상단 노드를 poll하여, 해당 값을 answer에 더해준다.
이때, 프로그래머스 페이지에 나와있는 그림들을 참고하여, 대입식을 짜서 answer에 더해준다.
이러한 과정들을 job idx가 마지막까지 가르키게 하여, 걸리는 총 시간 answer를 배열의 길이만큼 나눠 평균을 구해준다.
소스코드
import java.util.*;
class Solution {
public int solution(int[][] jobs) {
int answer = 0;
int cnt = 0;
int job_idx = 0;
int end = 0;
Arrays.sort(jobs,(o1,o2) -> o1[0] - o2[0]);
PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2) -> o1[1] - o2[1]);
int time = 0;
while(cnt < jobs.length){
while(job_idx < jobs.length && jobs[job_idx][0] <= end){
pq.add(jobs[job_idx]);
job_idx++;
}
if(pq.isEmpty()){
end = jobs[job_idx][0];
}
else{
int[] temp = pq.poll();
answer += temp[1] + end - temp[0];
end += temp[1];
cnt++;
}
}
return (int)Math.floor(answer / jobs.length);
}
}
결과
채점결과
정확성: 100.0
합계: 100.0 / 100.0
후기
처음에 순수 heap으로 하려다가 머리가 아파 포기하고 구글 서칭을 했었던 것같은데, 그렇게 하기를 잘 한 것같다.
결국 주어진 시간내에 문제를 풀어야하니까, 어떤 상황에서 어떤 자료구조를 사용해야 하는 지 아는 게 더 중요한 것같다.
'코딩 테스트' 카테고리의 다른 글
[백준 골드5] 12865번 평범한 배낭 / Java (0) | 2024.05.06 |
---|---|
[백준 골드3] 2830번 행성 X3 / Java (0) | 2024.04.23 |
[백준 실버5] 24174 알고리즘 수업 - 힙 정렬2 / Java (0) | 2024.04.21 |
[백준 실버4] 요세푸스 문제 / Java (1) | 2024.04.19 |
[프로그래머스 level2] 프로세스 / Java (0) | 2024.04.19 |