본문 바로가기
카테고리 없음

[Java][프로그래머스][알고리즘 고득점 Kit] 기능개발

by coding_whale 2026. 5. 4.
반응형

1. 문제

 

2. 도입부

소프트웨어 개발 현장에서는 여러 기능이 동시에 개발되지만, 배포는 순서대로 이루어져야 하는 경우가 많다. 먼저 개발이 완료된 기능이라도 앞에 있는 기능이 아직 작업 중이라면 기다려야 하고, 앞에 있는 기능이 배포될 때 함께 배포되는 구조다. 이러한 '선행 의존성'은 알고리즘 문제에서 아주 자주 등장하는 소재다. 오늘은 각 작업의 진도와 속도를 이용해 남은 작업일을 계산하고, 이를 배포 단위로 그룹화하는 논리적인 흐름을 정리해 본다.

3. 주요 특징 및 핵심 로직 

이 문제의 핵심은 '각 작업이 며칠 뒤에 끝나는가'를 먼저 구한 뒤, 앞에서부터 흐름을 타며 묶는 것이다.

  1. 잔여 작업일 계산: progresses와 speeds를 조합해 각 기능이 100%가 되기까지 필요한 일수(day)를 구한다.
  2. 배포 기준점(Current) 설정: 첫 번째 작업의 완료일을 기준으로 잡는다.
  3. 순차 비교 및 그룹화: 다음 작업들의 완료일이 기준점보다 작거나 같으면 한 배포에 묶고(count++), 더 오래 걸리는 작업을 만나면 새로운 배포 그룹을 시작한다.

구조 설명: 각 기능의 남은 일수가 [7, 3, 9]라고 할 때, 기준인 '7'보다 작은 '3'은 7일째에 함께 배포된다. 하지만 '9'는 7보다 크므로 새로운 배포 기준이 된다. 결과적으로 [2, 1]이라는 배포 묶음이 탄생한다.

 

4.  상세 가이드 및 심층 분석 (Detailed Guide)

🔍 STEP 1. 수학적 올림 처리를 이용한 일수 계산

작업 완료일을 구할 때 (100 - 현재진도) / 속도를 하면 소수점이 버려지는 문제가 생긴다. 보통 Math.ceil()을 쓰지만, 정수 연산만으로 올림을 처리하는 테크닉이 제공된 코드에 잘 녹아 있다.

  • 로직: (남은진도 + 속도 - 1) / 속도
  • 이유: 나누어떨어지지 않는 경우 나머지가 1이라도 존재하면 몫을 1 올리는 효과를 준다. 자바 정수 나눗셈의 특성을 이용한 아주 깔끔한 방식이다.

🔍 STEP 2. 기준일(current)과 비교 로직

배포는 무조건 인덱스 0번부터 순서대로 나가야 한다.

  • 첫 번째 기능의 완료일을 current 변수에 담고 시작한다.
  • 루프를 돌며 현재 기능의 완료일이 current 이하라면, 이미 배포 준비가 된 상태에서 앞 기능을 기다리는 것이므로 count를 올린다.
  • 만약 current보다 큰 값을 만나면, 앞선 그룹은 여기서 배포를 마감하고(list.add(count)), 새로운 기준일을 현재 값으로 갱신한다.

🔍 STEP 3. 가변 리스트를 배열로 변환

배포 그룹당 기능 수가 몇 개가 될지 미리 알 수 없으므로 List<Integer>에 저장한 뒤, 마지막에 Stream API를 활용해 int[]로 변환한다. 이는 동적인 결과를 요구하는 프로그래머스 문제 유형에 대응하는 정석적인 방법이다.

 

5. 구현 코드 (Java)

import java.util.*;

class Solution {
    public int[] solution(int[] progresses, int[] speeds) {
        List<Integer> list = new ArrayList<>();
        int n = progresses.length;
        int[] day = new int[n];
        
        // 1. 각 기능별 남은 작업 일수 계산 (정수 올림 테크닉)
        for(int i = 0; i < n; i++){
            // (100 - 현재진도)를 속도로 나눌 때 올림 처리
            day[i] = (100 - progresses[i] + speeds[i] - 1) / speeds[i];
        }
        
        // 2. 첫 번째 기능을 기준으로 배포 그룹 생성
        int current = day[0];
        int count = 1;
        
        for(int i = 1; i < n; i++){
            // 현재 작업이 기준 배포일 이전에 끝난다면 함께 배포
            if(day[i] <= current){
                count++;
            } else {
                // 더 오래 걸리는 작업을 만나면 이전 그룹 배포 확정
                list.add(count);
                // 기준일을 새로운 작업일로 갱신
                current = day[i];
                count = 1;
            }
        }
        
        // 마지막 남은 배포 그룹 추가
        list.add(count);
        
        // 3. List를 결과 배열로 변환하여 반환
        return list.stream().mapToInt(i -> i).toArray();
    }
}
반응형