[프로그래머스] 과제 진행하기

최민길(Gale)·2023년 7월 6일
1

알고리즘

목록 보기
88/172

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/176962

이 문제는 우선 순위 큐와 스택을 이용하여 문제 조건을 하나하나 구현해나가면 풀 수 있습니다. 이 문제의 조건이 굉장히 복잡하기 때문에 단순하게 생각하고 접근하다가는 꼬여 쉽게 풀 수 없게 됩니다. 따라서 차근차근 조건을 구현하는 능력을 길러야 합니다.

이 문제는 조건을 구현함과 동시에 현재 시간 업데이트 역시 매우 중요합니다. 우선 시간 빠른 순으로 정렬하기 위해 우선 순위 큐를 이용하여 시간값을 정렬합니다. 이 때 계산 편의를 위해 분 단위로 시간을 변환합니다. 우선 순위 큐에서 과제를 하나씩 뽑아내면서 1) 새로운 과제가 더 있는지 를 체크합니다. 만약 있을 경우 1-1) 다음 과제 정보를 가져오고 없을 경우 1-2) 현재 과제를 수행한 다음 멈춘 과제가 존재할 경우 멈춘 과제를 순서대로 수행합니다. 이 때 멈춘 과제는 가장 최근에 멈춘 과제 순으로 수행되기 때문에 스택을 사용하여 저장합니다.

이어서 새로운 과제가 더 있는 경우 2) 새로운 과제 수행 시간 전에 기존 과제를 끝낼 수 있는지 여부를 체크합니다. 만약 2-1) 새로운 과제 수행 시간 전에 기존 과제를 끝내고도 시간이 남는다면 현재 과제 정보를 정답에 추가한 후 현재 시간을 현재 과제 수행 시간만큼 더한 후 멈춘 과제를 탐색합니다. 만약 2-2) 기존 과제를 끝냈을 때 곧바로 새로운 과제 수행 시간이 되었다면 현재 과제 정보를 정답에 추가한 후 현재 시간을 과제 수행 시간만큼 더한 후 곧바로 다음 과제를 진행합니다. 만약 2-3) 과제를 새로운 과제 수행 시간 전까지 수행할 수 없다면 다음 과제 시작 시간과 현재 시간과의 차이만큼 수행시간을 감소시켜 스택에 저장합니다.

2-1)에서 멈춘 과제를 탐색할 때 3) 멈춘 과제를 남은 시간 내에 수행할 수 있는지를 확인합니다. 만약 3-1) 남은 시간 내에 수행 가능하다면 멈춘 과제를 정답에 추가한 후 현재 시간을 최신화합니다. 만약 3-2) 남은 시간 내에 과제를 수행할 수 없다면 수행 시간을 다음 과제 시간에서 현재 시간의 차이만큼 감소시켜 스택에 저장합니다. 여기서 주의할 점은 남은 시간 내에 과제를 여러 개 수행할 수 있기 때문에 반복문으로 처리하며 3-2)에 도달할 경우 break로 빠져나오면 되겠습니다.

다음은 코드입니다.

import java.util.*;

class Solution {
    static int CURR_TIME = 0;
    
    public List<String> solution(String[][] plans) {
        List<String> answer = new ArrayList<>();
        PriorityQueue<Homework> queue = new PriorityQueue<>();
        Stack<Homework> stack = new Stack<>();
        
        for(String[] plan : plans){
            String name = plan[0];
            int start = calTime(plan[1]);
            int playtime = Integer.parseInt(plan[2]);
            
            queue.add(new Homework(name,start,playtime));
        }
        
        while(!queue.isEmpty()){
            Homework curr = queue.poll();
            CURR_TIME = curr.time;
            
            // 만약 새로운 과제가 더 남아있다면
            if(!queue.isEmpty()){
                Homework next = queue.peek();
                
                // 만약 다음 과제 시작 전까지 과제를 끝내고 시간이 남는다면
                if(next.time > CURR_TIME + curr.playtime){
                    answer.add(curr.name);
                    CURR_TIME += curr.playtime;
                    
                    while(!stack.isEmpty()){
                        Homework remain = stack.pop();
                        
                        // 남는 시간 동안 멈춘 과제를 수행할 수 있는 경우
                        if(next.time >= CURR_TIME + remain.playtime){
                            answer.add(remain.name);
                            CURR_TIME += remain.playtime;
                        }
                        
                        // 남는 시간 동안 멈춘 과제를 다 수행할 수 없는 경우
                        else{
                            // 남은 시간만큼 수행 시간 감소 후 스택에 추가
                            remain.playtime -= next.time - CURR_TIME;
                            stack.add(remain);
                            break;
                        }
                    }
                    
                    
                }
                
                // 만약 현재 과제 끝내자마자 다음 과제 시작할 경우
                else if(next.time == CURR_TIME + curr.playtime){
                    answer.add(curr.name);
                    CURR_TIME += curr.playtime;
                    continue;
                }
                
                // 만약 다음 과제 시작 전까지 과제를 끝낼 수 없는 경우
                else{
                    // 남은 시간만큼 수행 시간 감소 후 스택에 추가
                    curr.playtime -= next.time - CURR_TIME;
                    stack.add(curr);
                }
                
            }
            
            // 남아있는 과제가 없다면
            else{
                // 현재 과제 수행
                answer.add(curr.name);
                
                // 멈춘 과제 수행
                if(!stack.isEmpty()){
                    while(!stack.isEmpty()){
                        answer.add(stack.pop().name);
                    }
                }
            }
            
        }
        
        return answer;
    }
    
    static int calTime(String time){
        String[] timeArr = time.split(":");
        int h = Integer.parseInt(timeArr[0]);
        int m = Integer.parseInt(timeArr[1]);
        return h*60 + m;
    }
    
    static class Homework implements Comparable<Homework>{
        String name;
        int time;
        int playtime;
        
        Homework(String name, int time, int playtime){
            this.name = name;
            this.time = time;
            this.playtime = playtime;
        }
        
        @Override
        public int compareTo(Homework o){
            return this.time - o.time;
        }
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보