Programmers
[프로그래머스 Level.3] 선입 선출 스케줄 (연습문제) (Java)
Devtraces
2023. 4. 9. 19:13
문제 링크
https://school.programmers.co.kr/learn/courses/30/lessons/12920
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
코딩테스트 연습 > 연습문제 > 선입 선출 스케줄
문제 설명
처리해야 할 동일한 작업이 n 개가 있고, 이를 처리하기 위한 CPU가 있습니다.
이 CPU는 다음과 같은 특징이 있습니다.
- CPU에는 여러 개의 코어가 있고, 코어별로 한 작업을 처리하는 시간이 다릅니다.
- 한 코어에서 작업이 끝나면 작업이 없는 코어가 바로 다음 작업을 수행합니다.
- 2개 이상의 코어가 남을 경우 앞의 코어부터 작업을 처리 합니다.
처리해야 될 작업의 개수 n과, 각 코어의 처리시간이 담긴 배열 cores 가 매개변수로 주어질 때, 마지막 작업을 처리하는 코어의 번호를 return 하는 solution 함수를 완성해주세요.
제한 사항
- 코어의 수는 10,000 이하 2이상 입니다.
- 코어당 작업을 처리하는 시간은 10,000이하 입니다.
- 처리해야 하는 일의 개수는 50,000개를 넘기지 않습니다.
입출력 예
n | cores | result |
6 | [1,2,3] | 2 |
입출력 예 설명
입출력 예 #1
처음 3개의 작업은 각각 1,2,3번에 들어가고, 1시간 뒤 1번 코어에 4번째 작업,다시 1시간 뒤 1,2번 코어에 5,6번째 작업이 들어가므로 2를 반환해주면 됩니다.
나의 코드
import java.util.*;
class Solution {
public int solution(int n, int[] cores) {
int answer = 0;
// target => 총 작업 시간
int start = 1;
int end = cores[0] * n; // 코어 한개가 n개의 일을 다하는 경우(최대)
int time = 0; // n개 이상의 작업이 처음으로 들어가는 시간
int count = 0;
while(start <= end) {
int mid = (start + end) / 2;
int sum = cores.length; // 처음에 코어에 작업이 각각 한 개씩 들어감
// 해당 시간(mid)까지 코어(core)가 완료한 일의 개수 합산
for(int core : cores) sum += mid / core;
if(sum >= n) {
end = mid - 1;
time = mid;
count = sum;
} else {
start = mid + 1;
}
}
count -= n; // 해당 시간(time)까지 들어간 작업과 n의 차이
for(int i=cores.length-1; i>=0; i--){
if(time % cores[i] == 0) { // 시간이 time일때, 작업을 끝내고 새로 시작한 core
if(count == 0) {
answer = i + 1;
break;
}
count--;
}
}
return answer;
}
}
풀이
- 이분 탐색(Binary Search)을 이용하여 n개 이상의 작업이 처음 시작되는 시간(time)을 구하고 해당 시간에 작업을 끝내고 새로 작업을 시작한 코어(core)들 중에 n번 째 작업을 시작한 코어(core)를 구한다.
- 우선 target을 n개 이상의 작업이 처음 시작되는 시간(time)으로 잡고 최선의 경우(start)를 1, 최악의 경우(end)를 한 개의 코어가 작업 n개를 모두 하는 경우인 core[0] * n으로 한다.
- n개 이상의 작업이 시작되는 시간을 구했을 때 해당 시간에 작업의 개수를 담을 count를 0으로 초기화한다.
- 이제 start가 end보다 커지면 종료하는 while문을 생성하고 start와 end를 더하고 2로 나눠 mid에 저장한다.
- 해당 mid의 시간 동안 작업한 진행하는 작업의 수를 저장할 int형 변수 sum을 core.length로 초기화 한다. (처음에 각 코어에 작업이 들어가므로 코어의 개수로 초기화)
- 그리고 각 코어가 cores를 순회하면서 mid / cores[i]를 이용해 해당 time까지 완료한 작업의 양을 sum에 더해준다.
- 그러면 sum에는 해당 시간(time)에 작업에 들어간 양이 담기게 된다.(time이 2초라면 2초까지 완료한 작업 + 작업 중인 작업)
- 이제 sum과 n을 비교하여 sum이 n 이상이라면 time을 mid로 저장하고 count에 sun을 저장한 후에 end를 mid - 1로 변경하여 n 이상의 작업을 시작하는 더 최선의 시간(time)을 찾고 sum이 n보다 작다면 start를 mid + 1로 변경하여 가능한 시간(time)을 다시 탐색한다.
- 이분 탐색을 마치고 해당 시간(time)을 찾았다면 이제 해당 시간에 들어간 n 이상의 작업인 count에서 n을 뺀다. (count에서 n을 빼면 해당 시간까지 들어간 작업량과 n의 차를 구할 수 있다)
- 해당 시간에 작업을 들어감으로써 처음으로 n 이상이 된 것이므로 이 둘의 차는 해당 시간 time에 새로 시작한 작업의 수와 같다.
- 동시에 작업이 끝난다면 앞의 코어부터 작업을 시작하므로 cores를 뒤에서부터 순회하면서 (time % cores[i] == 0)을 이용하여 해당 시간에 작업이 끝나 작업을 새로 시작하는 코어(작업이 끝나면 곧바로 새로 작업 시작)를 찾는다.
- 만약 count가 0이라면 해당 코어의 번호인 인덱스 + 1을 answer에 저장하고 반환하고 아니라면 count를 - 1 하고 앞의 코어를 탐색하여 n번 째 작업을 시작하는 코어의 번호를 구해 answer에 저장하고 반환하면 된다.
참고 : https://rays-space.tistory.com/15