프로그래머스 기능개발

작업 진도와 직업 속도가 주어졌을 때, 완료된 작업을 배포할 때마다 배포해야 할 작업 수를 구하는 문제이다. 배포는 모든 작업이 완료되어 배포될 때까지 진행한다.

입출력 예
progresses speeds return
[93,30,55] [1,30,5] [2,1]
@Test
public void test() {
    assertThat(solution(new int[]{93, 30, 55}, new int[]{1, 30, 5})).isEqualTo(new int[]{2, 1});
}

private int[] solution(int[] progresses, int[] speeds) {
    Queue<Task> queue = new LinkedList<>();

    for (int i = 0; i < progresses.length; i++) {
        queue.add(new Task(progresses[i], speeds[i]));
    }

    List<Integer> result = new ArrayList<>();
    while (!queue.isEmpty()) {
        for (Task task : queue) {
            task.startDevelopment();
        }

        int count = 0;
        for (Task oper : queue) {
            if (oper.isComplete()) {
                count++;
            } else {
                break;
            }
        }

        if (count > 0) {
            for (int i = 0; i < count; i++) {
                queue.poll();
            }
            result.add(count);
        }
    }

    return result.stream().mapToInt(i -> i).toArray();
}

class Task {
    int progress;
    int speed;
    public Task(int progress, int speed) {
        this.progress = progress;
        this.speed = speed;
    }

    public void startDevelopment() {
        if (this.progress < 100) this.progress += this.speed;
    }

    public boolean isComplete() {
        return this.progress >= 100;
    }
}
  • 0일: [93, 30, 55]
  • 1일: [94, 60, 60]
  • 2일: [95, 90, 65]
  • 3일: [96, 120, 70]
  • 4일: [97, 120, 75]
  • 5일: [98, 120, 80]
  • 6일: [99, 120, 85]
  • 7일: [100, 120, 90]
    • 첫 번째 기능과 두 번째 기능 배포
    • 큐: [90], 결과: [2]
  • 8일: [95]
  • 9일: [100]
    • 세 번째 기능 배포
    • 큐: [], 결과: [2, 1]

앞에 있는 기능부터 배포되기 때문에 큐를 사용한다. 반복문에서 작업 개발을 진행하면서 앞에서부터 완료된 작업의 개수를 누적하여 결과에 추가한다.

다른 사람이 작성한 더 간단한 해결법이 있다.

private int[] developOperations(int[] progresses, int[] speeds) {
    int[] dayOfEnd = new int[100];
    int day = -1;

    for (int i = 0; i < progresses.length; i++) {
        while (progresses[i] + (day * speeds[i]) < 100) {
            day++;
        }
        dayOfEnd[day]++;
    }

    return Arrays.stream(dayOfEnd).filter(i -> i!=0).toArray();
}

문제에 주어진 제한 사항을 이용한다. 작업의 진도가 1, 작업속도가 1이라면 최대 99일까지 진행할 수 있다. while문에서 배열의 앞에 위치한 작업이 완료되는 날까지 진행한다. 작업이 완료되는 날이 되면 해당 일자에 완료된 작업을 누적하기 위해 1을 증가시킨다. 다음 작업으로 넘어갔을 때, 이미 해당 작업이 완료할 수 있는 상태라면 while문이 수행되지 않는다.

  • 7일
    • 첫 번째 작업: 93 + (7 * 1) = 100 < 100, while문 빠져나옴
      • dayOfEnd[7] = 1
    • 두 번째 작업: 30 + (7 * 30) = 240 < 100, while문 빠져나옴
      • dayOfEnd[7] = 2
  • 9일
    • 세 번째 작업: 55 + (9 * 5) = 100 < 100, while문 빠져나옴
      • dayOfEnd[9] = 2
  • Arrays.stream(dayOfEnd).filter(i -> i!=0).toArray()
    • 7일과 9일을 제외하고 필터링: [2, 1]