해당 문제는 2021 KAKAO BLIND RECRUITMENT 출제 문제로 공식 해설이 있습니다.
2021 카카오 신입공채 1차 온라인 코딩 테스트 for Tech developers 문제해설
해설
1) 가장 많은 줄이 겹치는 지점이나 구간을 구할 때 떠올리면 좋은 스킬이 있다.
바로, 모든 로그의 시작점과 끝점에 대하여 (시작, +1), (끝, -1)을 저장한 배열을 만들고 해당 배열을 정렬하여 특정 포인트에 몇개의 +1과 -1이 추가 되는지 검사하는 것이다. 시간 t 지점에 겹치는 재생 목록이 n개인데 새로 시작되는 재생목록이 plus개, 끝나는 재생목록이 minus개라면 t+1 지점에는 겹치는 재생목록이 n+plus-minus 개가 된다.
log 배열을 이용하여 시간 t에 도달했을 때 추가되는 재생목록의 개수(재생시간의 합)을 rec[t]에 저장하자.
2) 각 시간에서 추가되는 재생목록의 수를 구해놓았다면, 슬라이딩 윈도우 기법을 이용해 크기가 adv_time(at)인 구간의 최대 합을 구하면 된다. 먼저, (0, at]까지의 재생시간 합(sum)을 구해놓자. 구간을 오른쪽으로 이동시킬 때는, en을 오른쪽으로 이동함과 동시에 rec[en]을 추가한다. st도 오른쪽으로 이동시키고 rec[st]를 제거한다.
각 구간에서 도출된 sum 값 중에서 최댓값을 저장하여 리턴하면 정답이다.
주의 할 점
sum 값이 int 범위를 초과할 수 있으므로 자료형 long long을 사용해야 한다.
코드
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <tuple>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <iostream>
using namespace std;
using ii = pair<int, int>;
using iii = tuple<int, int, int>;
using ll = long long;
#define X first
#define Y second
ll mx;
int pt, at, ans;
int h1, m1, s1, h2, m2, s2;
vector<ii> vlog;
vector<int> rec(400000, 0);
int tosec(int h, int m, int s) {
return h*3600+m*60+s;
}
string tostr(int sec) {
char tmp[50];
int l = sprintf(tmp, "%02d:%02d:%02d", sec/3600, sec%3600/60, sec%3600%60);
return string(tmp, l);
}
void setConditions(const string& play_time, const string& adv_time, const vector<string>& logs) {
sscanf(play_time.c_str(), "%d:%d:%d", &h1, &m1, &s1);
pt = tosec(h1, m1, s1);
sscanf(adv_time.c_str(), "%d:%d:%d", &h1, &m1, &s1);
at = tosec(h1, m1, s1);
for (auto x : logs) {
sscanf(x.c_str(), "%d:%d:%d-%d:%d:%d", &h1, &m1, &s1, &h2, &m2, &s2);
int st = tosec(h1, m1, s1);
int en = tosec(h2, m2, s2);
vlog.push_back({st, +1});
vlog.push_back({en, -1});
}
sort(vlog.begin(), vlog.end());
}
//각 시간대를 포함할 때 누적되는 재생시간을 구해 rec[t]에 저장
void setRec() {
int t = 0, idx = 0, cnt = 0;
while (t <= pt) {
int plus = 0, minus = 0;
while (idx < (int)vlog.size() && vlog[idx].X == t) {
if (vlog[idx].Y == +1) plus++;
else minus++;
idx++;
}
rec[t] = cnt;
cnt += (plus-minus);
t++;
}
}
//슬라이딩 윈도우로 크기가 at인 구간의 최대 합 구하기
void findStart() {
ll sum = 0;
int st = 0, en = 1;
//(0, at]까지의 합
while (en <= at) sum += rec[en++];
en--;
mx = sum;
//st와 en을 한칸씩 이동하여 합 갱신
while (en < pt) {
sum += rec[++en];
sum -= rec[++st];
if (sum > mx) { //합의 최댓값 저장
mx = sum;
ans = st;
}
}
}
string solution(string play_time, string adv_time, vector<string> logs) {
setConditions(play_time, adv_time, logs);
setRec();
findStart();
return tostr(ans);
}
'ㄴ 알고리즘 > 프로그래머스풀이' 카테고리의 다른 글
[프로그래머스 lv3] 모두 0으로 만들기 풀이 (0) | 2022.09.20 |
---|---|
[프로그래머스 lv3] 블록 이동하기 풀이 (0) | 2022.09.19 |
[프로그래머스 lv3] 스타 수열 풀이 (0) | 2022.09.18 |
[프로그래머스 lv3] N으로 표현 풀이 (0) | 2022.09.18 |
[프로그래머스 lv3] 거스름돈 풀이 (0) | 2022.09.18 |
댓글