성능 요약
- 메모리: 84.5 MB, 시간: 6.34 ms
구분
- 코딩테스트 연습 > 연습문제 > 우선순위 큐, 스택
Answer Code1(23.11.03)
import java.util.*;
class Solution {
static class Task {
private String name;
private int start;
private int playtime;
public Task(String name, int start, int playtime) {
this.name = name;
this.start = start;
this.playtime = playtime;
}
public Task(String name, int playtime) {
this.name = name;
this.playtime = playtime;
}
}
public List<String> solution(String[][] plans) {
// 정답을 저장할 리스트
List<String> answer = new ArrayList<>();
// 해야할 과제들을 시작시간 순으로 저장
PriorityQueue<Task> pq = new PriorityQueue<>(
(o1, o2) -> (o1.start - o2.start)
);
for(int i = 0; i < plans.length; i++) {
String name = plans[i][0];
String[] str = plans[i][1].split(":");
int h = Integer.parseInt(str[0]);
int m = Integer.parseInt(str[1]);
int start = (h * 60) + m; // '분' 기준으로 합침
int time = Integer.parseInt(plans[i][2]);
pq.add(new Task(name, start, time));
}
// 잠시 멈춘 과제를 저장
Stack<Task> remainingTasks = new Stack<>();
while(!pq.isEmpty()) {
Task currentTask = pq.poll();
String curName = currentTask.name;
int curStart = currentTask.start;
int curPlaytime = currentTask.playtime;
// 현재 시각
int currentTime = curStart;
// 1) 새로운 과제가 남아있는 경우(진행중이던 과제 제외)
if(!pq.isEmpty()) {
Task nextTask = pq.peek();
// 1-1) 지금 과제를 끝내고도 다음 과제 시작까지 시간이 남는 경우
if(currentTime + curPlaytime < nextTask.start) {
answer.add(curName);
currentTime += curPlaytime;
// 잠시 멈춘 과제가 있는 경우, 남는 시간동안 멈췄던 과제 해결
while(!remainingTasks.isEmpty()) {
Task rem = remainingTasks.pop();
// 다음 새로운 과제 시작전까지 다 끝낼수 있는 경우
if(currentTime + rem.playtime <= nextTask.start) {
currentTime += rem.playtime;
answer.add(rem.name);
continue;
}
// 다음 새로운 과제 시작전까지 못 끝내는 경우
else {
int t = rem.playtime - (nextTask.start - currentTime);
// 추가로 한 시간만 빼서 멈춘 과제 목록에 다시 추가
remainingTasks.push(new Task(rem.name, t));
break;
}
}
}
// 1-2) 지금 과제 끝내면 새로운 과제 시작할 시간인 경우
else if(curStart + curPlaytime == nextTask.start) {
answer.add(curName);
continue;
}
// 1-3) 새로운 과제 시작전까지 지금 과제를 못 끝내는 경우
else {
int t = (nextTask.start - currentTime);
remainingTasks.push(new Task(curName, curPlaytime - t));
}
}
// 2) 더 이상 남아있는 새로운 과제가 없는 경우
else {
// 2-1) 남아있는 과제(잠시 멈춘 과제)도 없는 경우
if(remainingTasks.isEmpty()) {
currentTime += curPlaytime;
answer.add(curName);
}
// 2-2) 남아있는 과제는 있는 경우
else {
answer.add(curName); // 새로운 과제부터 먼저 해결
// 남아있는 과제들을 정해진 순서대로 끝내면 됨
while(!remainingTasks.isEmpty()) {
Task rem = remainingTasks.pop();
answer.add(rem.name);
}
}
}
}
return answer;
}
}
문제풀이
과제를 진행할 때 과제의 시작 시각
(start)을 기준으로 하므로 PriorityQueue
를 사용해서 과제들의 정보를 시작 시간
순으로 저장합니다.
그리고 멈춰둔 과제가 여러 개 있는 경우 가장 최근에 멈춘 과제부터 시작한다는 점에서 멈춘 과제들을 저장하기 위해 Stack
을 사용했습니다.
새로운 과제와 잠시 멈춘 과제를 고려해서 여러 경우의 수를 생각하고, 각각의 상황에 따라 적합한 코드를 작성하여 문제를 해결하는 것이였습니다.
Review
구현에 대해 설명은 자세하나 그 속은 복잡한 문제였다.
경우의 수가 많고, 그에 따라 문제를 푸는데 헷갈려서 아이패드를 이용했다.
해당 문제를 나중에 다시 복습하면서, 우선순위 큐와 스택을 활용하는 것에 익숙해지자.