

1. 문제설명
프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.
또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.
먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.
제한 사항
- 작업의 개수(progresses, speeds배열의 길이)는 100개 이하입니다.
- 작업 진도는 100 미만의 자연수입니다.
- 작업 속도는 100 이하의 자연수입니다.
- 배포는 하루에 한 번만 할 수 있으며, 하루의 끝에 이루어진다고 가정합니다. 예를 들어 진도율이 95%인 작업의 개발 속도가 하루에 4%라면 배포는 2일 뒤에 이루어집니다.
입출력 예

입출력 예 설명
입출력 예 #1
첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능합니다.
두 번째 기능은 30%가 완료되어 있고 하루에 30%씩 작업이 가능하므로 3일간 작업 후 배포가 가능합니다. 하지만 이전 첫 번째 기능이 아직 완성된 상태가 아니기 때문에 첫 번째 기능이 배포되는 7일째 배포됩니다.
세 번째 기능은 55%가 완료되어 있고 하루에 5%씩 작업이 가능하므로 9일간 작업 후 배포가 가능합니다.
따라서 7일째에 2개의 기능, 9일째에 1개의 기능이 배포됩니다.
2. 접근방식
2-1. 문제 단순화
각 기능이 100프로 완성되었을 때 배포가능, 앞에 있는 기능이 완료되지 않으면 뒤에 있는 기능이 먼저 완료되더라도 기다려야 함.
각 배포마다 한 번에 몇 개의 기능이 나가는지 계산하기
각각의 기능이 완료되기까지 며칠 걸리는지 계산(작업 일수)
같이 나갈 수 있는 기능 묶기(배포 시점)
=> 결과 : 한 번에 몇 개의 기능이 배포되는지 계산
✅ 작업일수
- 첫 번째 기능이 100프로가 되려면 (100 - 93) / 1 = 7 일
- 두 번째 기능은 (100 - 30) / 30 = 2.xx 일 = 3 일 (올림)
- 세 번째 기능은 (100 - 55) / 5 = 9 일
- 따라서 작업 일수 계산은 Math.ceil((100 - progress[i]) / speeds[i])
✅ 배포 시점
- 첫 번째 기능은 7일째에 완료된다.
- 두 번째 기능은 3일 만에 준비되지만, 첫 번째 기능이 아직 준비되지 않았기 때문에 7일째에 같이 나간다.
- 세 번째 기능은 9일째에 준비되기 때문에 첫 번째 배포가 끝난 후, 9일째에 따로 나간다.
✅ 결과
- 첫 번째 배포는 두 개의 기능 [93, 30]
- 두 번째 배포는 한 개의 기능 [55]
- 따라서 리턴할 값은 [2, 1]
2-2. 해결법
명색이 스택/큐 문제이므로 큐로 풀어 준다. 여기서 큐(Queue)를 쓰는 이유는 문제에서 기능들을 순서대로 배포해야 되기 때문이다. 먼저 작업된 기능이 먼저 처리되고, 나중에 작업된 기능은 뒤에 처리되어야 하기 때문에 선입선출(FIFO)구조인 큐(Queue)를 이용한다.
1. 각 작업이 완료될 때까지 걸리는 일수를 계산해서 Queue에 저장
2. 큐가 비어 있지 않은 동안 loop를 돌리며 아래 작업 반복
3. 배포 그룹의 기준이 되는 최대 완료 일수를 나타내는 변수 currentMax 선언해 주고 첫 번째 작업의 완료 일수를 담아 준다. 이 값보다 늦게 완료되는 작업은 이번 배포에 포함되지 않고, 이 값 이하로 완료되는 작업들만 함께 배포.
4. 현재 배포에서 같이 배포되는 기능의 개수를 세는 변수 cnt = 1 로 초기화
5. workDays.peek()으로 큐의 맨 앞에 있는 값이 currentMax보다 작거나 같다면, 그 작업은 이번 배포에 포함되어야 함.
6. 현재 배포가 끝나면 결과 리스트에 cnt 값을 담아 주기
7. 리스트를 배열로 변환 후 return
3. 문제풀이
poll()은 큐의 맨 앞에 있는 요소를 반환하고 제거 함.
peek()은 요소를 반환하지만 제거 하지는 않는다.
잉? 첫번째로 제출한 코드가 틀렸다고 한다..
틀린 코드
import java.util.*;
class Solution {
public int[] solution(int[] progresses, int[] speeds) {
ArrayList<Integer> answer = new ArrayList<>();
Queue<Integer> workDays = new LinkedList<>();
// 각 작업이 완료되기까지 필요한 일수를 계산하여 큐에 추가
for (int i = 0; i < progresses.length; i++) {
// 첫 번째 작업의 완료 일수를 기준으로 설정
int days = (int) Math.ceil((100 - progresses[i]) / speeds[i]);
// 현재 배포에 포함될 기능의 수 초기화
workDays.add(days);
}
// 배포 처리
while(!workDays.isEmpty()) {
int currentMax = workDays.poll();
int cnt = 1;
// 기준일(currentMax)보다 빨리 끝나는 작업은 함께 배포
while(!workDays.isEmpty() && workDays.peek() <= currentMax) {
workDays.poll(); // 작업 제거
cnt++; // 배포 수 증가
}
// 현재 배포에 포함된 기능의 수 추가
answer.add(cnt);
}
// ArrayList -> int[]로 변환
return answer.stream().mapToInt(i -> i).toArray();
}
}

말 그대로 90점 짜리 코드 어디가 틀렸지?
아.... int days = (int) Math.ceil((100-progresses[i]) / speeds[i]); 부분이 틀렸다.
맞는 코드는 int days = (int) Math.ceil((100.0-progresses[i]) / speeds[i]);
정수 나눗셈이랑 실수 나눗셈 했을 때 Math.ceil 결과가 다르기 때문...
내가 처음 쓴 코드에서 (100 - progresses[i]) / speeds[i] 은 정수끼리의 나눗셈으로 두 정수를 나누면 결과도 정수이고, 소수점 이하의 값은 그냥 버려진다. 반면, Math.ceil()은 실수(double)로 계산된 값을 올림 처리하기 때문에 결과값에 근소한 차이가 생긴다.
그래서 100 대신 100.0을 사용하여 실수 나눗셈을 하는 것이 정확하다. 실제로 코드를 돌려 보았을 때도 테스트 케이스 10개는 통과했으나 한개는 통과하지 못한 걸로 봐 이 부분을 고려해서 문제를 낸 것 같다.
예를 들어, 100 - 95 = 5이고, speeds[i] = 2일 경우
정수 나눗셈: 5 / 2는 2 (소수점 이하 버림)
실수 나눗셈: 5.0 / 2 = 2.5 → Math.ceil(2.5)는 3 (정확한 올림)
정답 코드
import java.util.*;
class Solution {
public int[] solution(int[] progresses, int[] speeds) {
ArrayList<Integer> answer = new ArrayList<>();
Queue<Integer> workDays = new LinkedList<>();
// 각 작업이 완료되기까지 필요한 일수를 계산하여 큐에 추가
for (int i = 0; i < progresses.length; i++) {
// 첫 번째 작업의 완료 일수를 기준으로 설정
int days = (int) Math.ceil((100.0 - progresses[i]) / speeds[i]);
// 현재 배포에 포함될 기능의 수 초기화
workDays.add(days);
}
// 배포 처리
while(!workDays.isEmpty()) {
int currentMax = workDays.poll();
int cnt = 1;
// 기준일(currentMax)보다 빨리 끝나는 작업은 함께 배포
while(!workDays.isEmpty() && workDays.peek() <= currentMax) {
workDays.poll(); // 작업 제거
cnt++; // 배포 수 증가
}
// 현재 배포에 포함된 기능의 수 추가
answer.add(cnt);
}
// ArrayList -> int[]로 변환
return answer.stream().mapToInt(i -> i).toArray();
}
}
4. 같은 유형 문제(스택/큐)
[프로그래머스] (Java) 주식가격 (스택/큐)
📑 1. 문제설명💡 2. 접근방식이중for문현재 인덱스에 있는 요소과 이후 모든 값을 비교하면서 현재 요소가 비교하고 있는 요소보다 커지면 break;를 걸어준다. 그 전까지는 answer[i]++을 해 준다.
awesomepossum.tistory.com
[프로그래머스] (Java) 다리를 지나는 트럭 (스택/큐)
📑 1. 문제설명💡 2. 접근방식 Queue트럭 진입 로직: 다리의 맨 앞 트럭이 나가고 새로운 트럭이 다리에 올라갈 수 있는지 확인한 후 다리에 추가이동시간: 트럭이 다리 위에 오르면 매 1초마다
awesomepossum.tistory.com
[프로그래머스] (Java) 프로세스 문제풀이 (스택/큐)
1. 문제설명 예제 #1문제에 나온 예와 같습니다. 예제 #26개의 프로세스 [A, B, C, D, E, F]가 대기 큐에 있고 중요도가 [1, 1, 9, 1, 1, 1] 이므로 [C, D, E, F, A, B] 순으로 실행됩니다. 따라서 A는 5번째로 실
awesomepossum.tistory.com
[프로그래머스] (Java) 올바른 괄호 문제풀이 (스택/큐)
1. 문제설명2. 접근방식1) 스택을 사용하지 않고 풀기문자열을 순회하며 닫힌 괄호와 열린 괄호의 갯수를 변수에 저장하고 개수가 같으면 true, 틀리면 false 를 반환하는 방법 2) 스택을 사용하여
awesomepossum.tistory.com
[프로그래머스] (Java) 같은 숫자는 싫어 문제 풀이 (스택/큐)
1. 문제설명배열 arr가 주어집니다. 배열 arr의 각 원소는 숫자 0부터 9까지로 이루어져 있습니다. 이때, 배열 arr에서 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하려고 합니다. 단, 제거
awesomepossum.tistory.com
'코딩테스트 > 알고리즘베스트' 카테고리의 다른 글
| [프로그래머스] (Java) 프로세스 문제풀이 (큐) (4) | 2024.11.09 |
|---|---|
| [프로그래머스] (Java) 올바른 괄호 문제풀이 (스택) (9) | 2024.11.08 |
| [프로그래머스] (Java) 같은 숫자는 싫어 문제 풀이 (스택) (9) | 2024.11.06 |
| [프로그래머스] (Java) H-INDEX (정렬) (6) | 2024.11.02 |
| [프로그래머스] (Java) 가장 큰 수 문제 풀이 (정렬) - compareTo() 메서드 (3) | 2024.11.02 |