우당탕탕 개발일지

[프로그래머스] 과제 진행하기(Java, Level.2) 본문

코테/프로그래머스

[프로그래머스] 과제 진행하기(Java, Level.2)

ujin302 2024. 5. 3. 22:41
반응형

문제

과제는 시작하기로 한 시각이 되면 시작합니다.
새로운 과제를 시작할 시각이 되었을 때, 기존에 진행 중이던 과제가 있다면 진행 중이던 과제를 멈추고 새로운 과제를 시작합니다.


진행중이던 과제를 끝냈을 때, 잠시 멈춘 과제가 있다면, 멈춰둔 과제를 이어서 진행합니다. 만약, 과제를 끝낸 시각에 새로 시작해야 되는 과제와 잠시 멈춰둔 과제가 모두 있다면, 새로 시작해야 하는 과제부터 진행합니다.

 

멈춰둔 과제가 여러 개일 경우, 가장 최근에 멈춘 과제부터 시작합니다.

 

과제 계획을 담은 이차원 문자열 배열 plans가 매개변수로 주어질 때, 과제를 끝낸 순서대로 이름을 배열에 담아 return 하는 solution 함수를 완성해주세요.

 

입출력 예

 

 

풀이

 

위의 사진은 예제 2번을 가지고 과제 수행을 표로 표현해 봤다. ()안의 숫자는 남은 시간이며 노란색은 완료한 과제이다. 

 

[ 문제 해설 ]

1. 시간은 분단위 기준!

2. 시작 시간대로 오름차순 정렬
3. 과제 중단되는 경우

    >> 마지막 과제 아님
    >> 현재과제 시작시간 + paly 시간 > 다음과제 시작 시간

3-1. 과제 중단 O

  • 중단된 과제 stack에 저장 (name, 남은 시간)
  • 다음 과제 시작
  • 현재 시간 = 다음과제 시작 시간

3-2. 과제 중단 X

  • answer에 저장
  • 다음 과제 시작

 

4. 다음과제 시작까지 시간이 남은 경우

    >> 마지막 과제 아님
    >> 현재시간 + 중단된 과제 남은 수행시간 <= 다음 과제 시작 시간 

    >> 중단된 과제 남은 수행시간은 stack에서 가져옴

 

4-1. 1개 이상의 과제 수행 완료

  • 과제 하나 끝날때마다 answer 과제에 저장
  • 과제 완료 개수 ++ 
  • 현재 시간 += 중단된 과제 남은 수행시간
  • 남은 시간동안 2개 이상 수행할 수도 있기에 다음 과제 시작 시간이 아닌 남은 수행시간 더함. 

4-2. 1개를 완료하지 못했을 경우 stack에 다시 저장

  • 현재 시간 = 다음 과제 시작 시간 
  • stack에 완료하지 못한 과제명과 남은 시간 저장
  • 남은 시간 -= (다음과제 시작 시간 - 현재 시간)


5. 주어진 plan이 끝남 && stack에 중단된 과제 남음
    >> 중단되 과제 순서대로 완료하여 answer에 저장

 

 

[ 코드 풀이 ]

위의 5가지 순서를 지킨다. 

1번 

toSec 함수를 통해서 분 단위로 변환 

 

2번 

sort 함수를 통해 시작시간 기준으로 오름차순 정렬 

 

현재 과제 설정 

현재 과제명, 시작시간, 수행시간 설정

현재 시간은 현재 과제의 종료 시간으로 설정 

 

 

3-1번 

마지막 과제인지 판단 필요 >> 다음과제의 시작시간을 가져오기에 배열의 index를 넘어서 발생하는 오류 방지 

 

과제 중단되는 경우는 현재 과제시간이 다음과제 시간 시간보다 클 경우!

중단된 과제를 stack에 저장 (과제명, 남은 수행 시간)

 

 plans배열의 다음 과제를 위한 index ++ 

countinue를 통해 다음과제 진행 (해당 조건문 밑에는 과제가 완료된 경우 작업 진행됨)

 

3-2번

3-1번에 해당하지 않을 경우에는 주어진 시간 안에 과제가 완료할 수 있다고 판단

따라서 완료과제 저장 

완료된 과제 개수 설정 

다음과제를 위해 index++ 

4번 

(나는 이부분에서 너무 괴로워따....ㅠ)

 

해당 부분은 중단된 과제가 존재할 경우에만 해당한다. 

stack에서 과제 하나를 가지고 와 남은 수행시간을 int형으로 변환 

 

해당 부분에서 4-1과 4-2로 나뉜다. 

먼저 4-1이다. 

중단된 과제의 남은 수행시간이 다음과제 시간과 같거나 작을때에만 적응된다. 

해당 경우 완료된 과제임으로 answer에 저장하며 완료된 과제 개수도 설정한다. 

 

현재 시간은 기존 현재시간에 중단된 과제의 남은 수행시간을 더한다. 

해당 부분에서 다음과제 시작시간으로 설정하지 않은 이유는 남은 시간동안 2개 이상의 과제를 완료할 수 있기도 하기 때문이다. 

따라서 꼭 중단된 과제의 남은 수행시간을 더해줘야 한다. 

 

 

4-2 부분은 다시 중단되었을 경우로 else에 해당한다. 

다시 중단이 되었기에 stack에 과제 정보를 추가한다. 

이때 남은 과제 시간을 다시 설정해줘야 한다. 

남은 과제 시간은 다음과제 수행시간까지의 시간을 뺀다.

 

그 후, break를 통해 while문을 빠져나간다. 

stack에 남은 과제가 있더라도 다음과제가 시작해야하기 때문에 더이상 중단된 과제를 수행할 수 없다. 

시간을 설정하지 않은 이유는 while문 시작시 현재 시간을 설정하기 때문이다. 

만약 마지막 과제라면 while문을 벗어나기 때문에 시간 설정을 진행하지 않는다. 

 

 

5번

해당 부분은 4-1과 동일하다. 

이 부분은 주어진 plan 배열의 모든 과제들을 한번씩 수행했음에도 불구하고 중단된 과제 있을 경우에 진행하게 된다. 

stack에서 과제 하나씩 가져와 차례대로 과제명을 answer에 저장한다. 

 

그 후 저장된 과제 배열 answer를 반환한다. 

 

 

코드

public int toSec(String time) {
        int h = Integer.parseInt(time.split(":")[0]) * 60;
        int m = Integer.parseInt(time.split(":")[1]);

        return h + m;
    }

    public String[] s2_2(String[][] plans) {
        // 1. 변수 설정
        int len = plans.length; // paln 길이
        String[] answer = new String[len]; // 완료된 과제
        Stack<String[]> stopStack = new Stack<>(); // 중단된 과제
        Arrays.sort(plans, (o1, o2) -> toSec(o1[1]) - toSec(o2[1])); // 오름차순

        // 2. 현재 과제
        String name = ""; // 현재 과제
        int startTime = 0; // 현재 과제 시작 시간
        int playTime = 0; // 현재 과제 수행 시간
        int index = 0; // 현재 과제 번호

        // 3. 시간 변수
        int currentTime = 0; // 현재 시간 (현재 과제 끝나는 시간)

        // 4. 다음 과제
        int nextStart = 0; // 다음 과제 시작 시간
        int count = 0; // 완료된 과제 개수

        // 5. 과제 진행
        while (len > index) {
            // 1. 현재 과제 설정
            name = plans[index][0];
            startTime = toSec(plans[index][1]);
            playTime = Integer.parseInt(plans[index][2]);
            currentTime = startTime + playTime;

            // 2. 과제 중단 O (3-1)
            if (index + 1 < len) { // 마지막 과제 아님
                nextStart = toSec(plans[index + 1][1]); // 다음과제 시작 시간
                if (currentTime > nextStart) { // 현재과제 시작시간 + paly 시간 > 다음과제 시작 시간

                    // 2-1. 중단된 과제 저장
                    int remain = playTime - (nextStart - startTime); // 남은 시간
                    stopStack.push(new String[] { name, remain + "" });
                    currentTime = nextStart;
                    // 2-2. 과제 중단으로 인해 다음과제 진행
                    index++;
                    continue;
                }
            }

            // 3. 과제 중단 X (3-2)
            answer[count] = name; // 과제 완료
            count++; // 완료된 과제 개수
            index++; // 다음 과제 설정

            // 4. 다음 과제까지 남는 시간 (4)
            while (!stopStack.empty()) { // 중단된 과제 존재
                if (currentTime < nextStart) { // 다음 과제까지 시간 남음
                    String[] stopStrArr = stopStack.pop();
                    int remain_time = nextStart - currentTime; // 다음 과제까지 남는 시간

                    // 또 중단 (4-2)
                    if (Integer.parseInt(stopStrArr[1]) - remain_time > 0) {
                        // 주어진 남은 시간보다 수행 시간이 더 오래걸리는 경우
                        stopStrArr[1] = Integer.parseInt(stopStrArr[1]) - remain_time + "";
                        stopStack.push(stopStrArr); // 다시 중단됨
                        currentTime = nextStart;
                        break;
                    } else { // 주어진 시간 동안 완료 (4-1)
                        answer[count] = name;
                        count++;
                        currentTime = nextStart;
                    }
                }
                break;
            }
        }

        //
        while (!stopStack.empty()) { // 중단된 과제 존재
            String[] stopStrArr = stopStack.pop();
            answer[count] = stopStrArr[0];
            count++;
        }

        return answer;

 

 

프로그래머스 문제 

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

 

반응형