본문 바로가기
Algorithm

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

by brother_stone 2023. 12. 20.

https://school.programmers.co.kr/learn/courses/30/lessons/176962

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

시나리오

 

1. 시작시간을 기준으로 내림차순 정렬

2. progress, pause스택을 생성한 뒤 정렬된 homework배열을 progress에 모두 삽입

3-1. progress.size() > 1일 때까지 순회하며 progress를 pop하고 pop한 과제의 시작시간 + 남은시간과 peek()의 시작시간을 비교, 전자가 클 경우 잠시 중단하고 다음 과제를 해야하기 때문에 pop한 과제의 남은 시간 갱신하고 pause스택에 push 한다.

3-2.  후자가 클 경우 다음 과제 시작 전 현재 과제가 끝난다는 의미로 pop한 과제의 subject를 answer에 삽입, pause에 과제가 있다면 순서대로 freeTime만큼 과제를 수행한다.

4. while문을 빠져나온 뒤 pause가 비어있지 않다면 freeTime을 다 소진하여 pause의 과제를 끝낼 수 있는지 확인.

5. 위 과정이 끝난 뒤 progress의 남은 과제를 answer에 삽입하고 다시 pause에 남은 과제가 있는지 확인 후 있다면 answer에 삽입한다.

* freeTime: 다음 과제의 시작 시간 - 현재 과제의 시작 시간 + 남은 시간(현재 과제의 시작 시간 + 남은 시간< 다음 과제의 시작 시간 일때)

 

처음 코드

import java.util.*;

class Solution {
    public String[] solution(String[][] plans) {
        String[] answer = new String[plans.length];
        int idx = 0;
        String criteriaTime = "";
        
        Homework[] homeworks = new Homework[plans.length];
        
        //1. Homework타입 배열에 삽입
        for(int i=0; i<plans.length; i++){
            String[] plan = plans[i];
            homeworks[i]=new Homework(plan[0], removeColon(plan[1]),Integer.parseInt(plan[2]));
        }
        
        //2. 정렬
        Arrays.sort(homeworks);
        
        //3. stack생성
        Stack<Homework> progress = new Stack<>();
        Stack<Homework> pause = new Stack<>();
        
        Arrays.stream(homeworks).forEach(h->progress.push(h));
        
        //4.로직 수행
        while(progress.size()>1){
            Homework popped = progress.pop();
            
            criteriaTime = progress.peek().startTime;
            int subTime = subtract(criteriaTime, popped.startTime);
            
            if(subTime < popped.restTime){
                popped.restTime -= subTime;
                pause.push(popped);
                continue;
            }
            answer[idx++]=popped.subject;
            
            criteriaTime = add(popped.startTime,popped.restTime);
            
            if(!pause.isEmpty()){
                int res =  subtract(progress.peek().startTime, criteriaTime);
                if(res >= pause.peek().restTime){
                    answer[idx++]=pause.pop().subject;
                    
                    continue;
                }
                pause.peek().restTime-=res;
            }
        }
        if(!progress.isEmpty()){
            answer[idx++]=progress.pop().subject;
            
            while(!pause.isEmpty()){
                answer[idx++] = pause.pop().subject;
            }
        }
        
        return answer;
    }

    private int subtract(String time1, String time2){
        String[] splitedT1 = splitTime(time1);
        String[] splitedT2 = splitTime(time2);
        
        int h = (Integer.parseInt(splitedT1[0])-Integer.parseInt(splitedT2[0]))*60;
        int m = (Integer.parseInt(splitedT1[1])-Integer.parseInt(splitedT2[1]));
        
        return h+m;
    }
    
    private String add(String time1, int minute){
        StringBuilder sb = new StringBuilder();
        
        String[] splitedT1 = splitTime(time1);
        
        int h = Integer.parseInt(splitedT1[0])*60;
        int m = Integer.parseInt(splitedT1[1])+minute;
        
        if(m>=60){
            h++;
            m-=60;
        }
            sb.append(h);
            sb.append(m);
        
        return sb.toString();
    }
    
    private String[] splitTime(String time){
        String[] result = new String[2];

        result[0] = new StringBuilder().append(time.charAt(0)).append(time.charAt(1)).toString();
        result[1] = new StringBuilder().append(time.charAt(2)).append(time.charAt(3)).toString();
        
        return result;
    }
    
    private String removeColon(String time){
        String[] t = time.split(":");
        return new StringBuilder().append(t[0]).append(t[1]).toString();
    }
    
    class Homework implements Comparable<Homework>{
        String subject;
        String startTime;
        int restTime;
        
        public Homework(String subject, String startTime, int restTime){
            this.subject = subject;
            this.startTime = startTime;
            this.restTime = restTime;
        }
        
        //내림차순
        @Override
        public int compareTo(Homework o){
            return Integer.parseInt(o.startTime)-Integer.parseInt(this.startTime);
        }
    }
}

 

개선한 코드(정답)

import java.util.*;

class Solution {
    public String[] solution(String[][] plans) {
        String[] answer = new String[plans.length];
        int idx = 0;
        int freeTime=0;
        
        Homework[] homeworks = new Homework[plans.length];
        
        //1. Homework타입 배열에 삽입
        for(int i=0; i<plans.length; i++){
            String[] plan = plans[i];
            homeworks[i]=new Homework(plan[0], convertMinute(plan[1]),Integer.parseInt(plan[2]));
        }
        
        //2. 정렬
        Arrays.sort(homeworks);
        
        //3. stack생성
        Stack<Homework> progress = new Stack<>();
        Stack<Homework> pause = new Stack<>();
        Arrays.stream(homeworks).forEach(h->progress.push(h));
        
        //4.로직 수행
        while(progress.size()>1){
            Homework popped = progress.pop();
            if(popped.startTime + popped.restTime > progress.peek().startTime){
                popped.restTime -= (progress.peek().startTime - popped.startTime);
                pause.push(popped);
            }else{
                answer[idx++] = popped.subject;
                freeTime = progress.peek().startTime - (popped.startTime + popped.restTime);
                while(!pause.isEmpty() && freeTime>0){
                    if(pause.peek().restTime > freeTime){
                        pause.peek().restTime -= freeTime;
                        freeTime=0;
                        break;
                    }
                    else{
                        Homework poppedHomework = pause.pop();
                        answer[idx++] = poppedHomework.subject;
                        freeTime-=poppedHomework.restTime;
                    }
                }
            }
        }
        
        if(!progress.isEmpty()){
            while(!pause.isEmpty() && freeTime>0){
                if(pause.peek().restTime > freeTime){
                    break;
                }
                
                Homework poppedHomework = pause.pop();
                answer[idx++] = poppedHomework.subject;
                freeTime-=poppedHomework.restTime;
            }
            
            answer[idx++]=progress.pop().subject;
            
            while(!pause.isEmpty()){
                answer[idx++] = pause.pop().subject;
            }
        }
        
        return answer;
    }
    
    private int convertMinute(String time){
        String[] t = time.split(":");
        return Integer.parseInt(t[0])*60+Integer.parseInt(t[1]);
    }
    
    class Homework implements Comparable<Homework>{
        String subject;
        int startTime;
        int restTime;
        
        public Homework(String subject, int startTime, int restTime){
            this.subject = subject;
            this.startTime = startTime;
            this.restTime = restTime;
        }
        
        //내림차순
        @Override
        public int compareTo(Homework o){
            return o.startTime-this.startTime;
        }
    }
}

 

 

기존 코드가 틀린 이유는 입력으로 주어진 시간을 처리하는 과정에서 예외가 발생했기 때문이다.

구글링결과 시간을 분단위로 미리 변환해놓으면 편리하다는 팁을 발견, 바로 적용했고 채점을 돌려보니 정답처리가 되었다.

기존 코드에서는 덧셈, 뺄셈하는 과정이 너무 복잡해 구현하는 것도 어려웠고 오류가 났을 때 찾기도 힘들었다. 앞으로 시간이 문자열로 주어지면 분단위로 변환해놓고 연산하자..