과제를 받은 루는 다음과 같은 순서대로 과제를 하려고 계획을 세웠습니다.
과제는 시작하기로 한 시각이 되면 시작합니다.
새로운 과제를 시작할 시각이 되었을 때, 기존에 진행 중이던 과제가 있다면 진행 중이던 과제를 멈추고 새로운 과제를 시작합니다.
진행중이던 과제를 끝냈을 때, 잠시 멈춘 과제가 있다면, 멈춰둔 과제를 이어서 진행합니다.
만약, 과제를 끝낸 시각에 새로 시작해야 되는 과제와 잠시 멈춰둔 과제가 모두 있다면, 새로 시작해야 하는 과제부터 진행합니다.
멈춰둔 과제가 여러 개일 경우, 가장 최근에 멈춘 과제부터 시작합니다.
과제 계획을 담은 이차원 문자열 배열 plans가 매개변수로 주어질 때, 과제를 끝낸 순서대로 이름을 배열에 담아 return 하는 solution 함수를 완성해주세요.
선점 스케쥴링이랑 비슷한데 다르다. 선점 스케줄링 느낌은 맞지만 OS 알고리즘이 아니라 ‘이벤트 기반 LIFO 시뮬레이션’ 문제이다.
우선 시간 사이의 간격을 구하기 위해 각 '11:30', '12:40' 과 같은 문자열을 전부 분(minutes)기반으로 변환했다.
ll convertMin(string s) {
ll hour = stoll(s.substr(0, 2));
ll min = stoll(s.substr(3,2));
return min + hour*60;
}
또한 과제 시각시간에 따라 정렬하는 것이 필요했으므로 정렬함수를 정의했다.
bool cmp(const vector<string>& a, const vector<string>& b) {
return stoll(a[1]) < stoll(b[1]);
}
sort(plans.begin(), plans.end(), cmp);
가독성을 위해서 현재 과제시작시간, 다음 과제시작시간, 현재 과제소요시간, 다음 과제시작시간까지의 남은 시간을 변수로 정의했다.
ll curTime = stoll(plans[i][1]);
ll nextTime = stoll(plans[i+1][1]);
ll duration = stoll(plans[i][2]);
ll available = nextTime - curTime;
이 문제의 핵심은
이 두 가지 조건이다.
따라서 멈춘 과제가 있다면 remain이라는 이름의 스택에 {과제명, 남은 시간}을 저장하는 방식으로 구현했다.
extra가 0보다 크고, 멈춘 과제가 존재한다면 남은 과제시간보다 extra가 크면 남은 과제시간에 extra 시간만큼 차감한 후 다시 push를 해주고, extra시간 안에 과제를 끝낼 수 있으면 결과 배열(answer)에 저장하고 extra시간을 과제 시간만큼 차감했다.
if (duration > available) {
remain.push({plans[i][0], duration - available});
} else {
answer.push_back(plans[i][0]);
ll extra = available - duration;
while (extra > 0 && !remain.empty()) {
auto [name, t] = remain.top();
remain.pop();
if (t > extra) {
remain.push({name, t - extra});
extra = 0;
} else {
answer.push_back(name);
extra -= t;
}
}
}
시뮬레이션 문제이다. 구현하는데 오랜 시간이 걸렸다. 문제풀이 시간을 단축하도록 하자.
#include <string>
#include <vector>
#include <stack>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
ll convertMin(string s) {
ll hour = stoll(s.substr(0, 2));
ll min = stoll(s.substr(3,2));
return min + hour*60;
}
bool cmp(const vector<string>& a, const vector<string>& b) {
return stoll(a[1]) < stoll(b[1]);
}
vector<string> solution(vector<vector<string>> plans) {
vector<string> answer;
stack<pair<string, ll>> remain;
for(int i=0; i<plans.size(); i++) {
plans[i][1] = to_string(convertMin(plans[i][1]));
}
sort(plans.begin(), plans.end(), cmp);
for (int i = 0; i < plans.size() - 1; i++) {
ll curTime = stoll(plans[i][1]);
ll nextTime = stoll(plans[i+1][1]);
ll duration = stoll(plans[i][2]);
ll available = nextTime - curTime;
if (duration > available) {
remain.push({plans[i][0], duration - available});
} else {
answer.push_back(plans[i][0]);
ll extra = available - duration;
while (extra > 0 && !remain.empty()) {
auto [name, t] = remain.top();
remain.pop();
if (t > extra) {
remain.push({name, t - extra});
extra = 0;
} else {
answer.push_back(name);
extra -= t;
}
}
}
}
answer.push_back(plans[plans.size()-1][0]);
while(!remain.empty()) {
auto a = remain.top();
remain.pop();
answer.push_back(a.first);
}
return answer;
}