문제 설명
추석 트래픽
이번 추석에도 시스템 장애가 없는 명절을 보내고 싶은 어피치는 서버를 증설해야 할지 고민이다. 장애 대비용 서버 증설 여부를 결정하기 위해 작년 추석 기간인 9월 15일 로그 데이터를 분석한 후 초당 최대 처리량을 계산해보기로 했다. 초당 최대 처리량은 요청의 응답 완료 여부에 관계없이 임의 시간부터 1초(=1,000밀리초)간 처리하는 요청의 최대 개수를 의미한다.
입력 형식
- solution 함수에 전달되는 lines 배열은 N(1 ≦ N ≦ 2,000)개의 로그 문자열로 되어 있으며, 각 로그 문자열마다 요청에 대한 응답완료시간 S와 처리시간 T가 공백으로 구분되어 있다.
- 응답완료시간 S는 작년 추석인 2016년 9월 15일만 포함하여 고정 길이 2016-09-15 hh:mm:ss.sss 형식으로 되어 있다.
- 처리시간 T는 0.1s, 0.312s, 2s 와 같이 최대 소수점 셋째 자리까지 기록하며 뒤에는 초 단위를 의미하는 s로 끝난다.
- 예를 들어, 로그 문자열 2016-09-15 03:10:33.020 0.011s은 "2016년 9월 15일 오전 3시 10분 33.010초"부터 "2016년 9월 15일 오전 3시 10분 33.020초"까지 "0.011초" 동안 처리된 요청을 의미한다. (처리시간은 시작시간과 끝시간을 포함)
- 서버에는 타임아웃이 3초로 적용되어 있기 때문에 처리시간은 0.001 ≦ T ≦ 3.000이다.
- lines 배열은 응답완료시간 S를 기준으로 오름차순 정렬되어 있다.
출력 형식
- solution 함수에서는 로그 데이터 lines 배열에 대해 초당 최대 처리량을 리턴한다.
입출력 예제
예제1
- 입력: [
"2016-09-15 01:00:04.001 2.0s",
"2016-09-15 01:00:07.000 2s"
] - 출력: 1
예제2
- 입력: [
"2016-09-15 01:00:04.002 2.0s",
"2016-09-15 01:00:07.000 2s"
] - 출력: 2
- 설명: 처리시간은 시작시간과 끝시간을 포함하므로
첫 번째 로그는 01:00:02.003 ~ 01:00:04.002에서 2초 동안 처리되었으며,
두 번째 로그는 01:00:05.001 ~ 01:00:07.000에서 2초 동안 처리된다.
따라서, 첫 번째 로그가 끝나는 시점과 두 번째 로그가 시작하는 시점의 구간인 01:00:04.002 ~ 01:00:05.001 1초 동안 최대 2개가 된다.
예제3
- 입력: [
"2016-09-15 20:59:57.421 0.351s",
"2016-09-15 20:59:58.233 1.181s",
"2016-09-15 20:59:58.299 0.8s",
"2016-09-15 20:59:58.688 1.041s",
"2016-09-15 20:59:59.591 1.412s",
"2016-09-15 21:00:00.464 1.466s",
"2016-09-15 21:00:00.741 1.581s",
"2016-09-15 21:00:00.748 2.31s",
"2016-09-15 21:00:00.966 0.381s",
"2016-09-15 21:00:02.066 2.62s"
] - 출력: 7
- 설명: 아래 타임라인 그림에서 빨간색으로 표시된 1초 각 구간의 처리량을 구해보면 (1)은 4개, (2)는 7개, (3)는 2개임을 알 수 있다. 따라서 초당 최대 처리량은 7이 되며, 동일한 최대 처리량을 갖는 1초 구간은 여러 개 존재할 수 있으므로 이 문제에서는 구간이 아닌 개수만 출력한다.
💚 나의 풀이
from datetime import timedelta, datetime
def cal(start, results) :
end=start+timedelta(seconds=1)
cnt=0
for result in results :
if result[0] < end and result[1] >= start :
cnt+=1
return cnt
def solution(lines):
answers=0
results=[]
for line in lines :
log=line.split()
end=log[0]+" "+log[1]
log[2]=log[2][:-1] # s 제거
end=datetime.fromisoformat(end)
start=end-timedelta(milliseconds=float(log[2])*1000-1)
results.append([start, end])
for result in results :
answers=max(answers, max(cal(result[0], results), cal(result[1], results)))
return answers
datetime.fromisoformat(date_string)
입력이 '2016-09-15 20:59:57.421'이면
출력은 '2016-09-15 20:59:57.421000'
timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
두 날짜 또는 시간의 차를 통해 기간을 나타냄.
start를 구할 때, -1을 하는 이유는 처리시간은 시작시간과 끝 시간을 포함해야한다고 문제 조건에 나와있어서다.
import java.util.*;
class Solution {
public int cal(double start, ArrayList<ArrayList<Double>> result){
double end=start+1000;
int cnt=0;
for(ArrayList<Double> i : result){
if(i.get(0) < end && i.get(1) >= start) cnt++;
}
return cnt;
}
public int solution(String[] lines) {
int answer = 0;
ArrayList<ArrayList<Double>> list=new ArrayList<ArrayList<Double>>();
for(String line : lines){
String[] date=line.split(" ");
date[2]=date[2].replace("s",""); // s제거
String[] end=date[1].split(":");
Double second=(Integer.parseInt(end[0])*3600 + Integer.parseInt(end[1])*60 + Double.parseDouble(end[2]))*1000;
Double start=second-(Double.parseDouble(date[2])*1000)+1;
ArrayList<Double> result=new ArrayList<>();
result.add(start);
result.add(second);
list.add(result);
}
for(ArrayList<Double> i : list){
answer=Math.max(answer, Math.max(cal(i.get(0), list), cal(i.get(1), list)));
}
return answer;
}
}
처리시간 date[2]에 *1000을 빼먹어서 테케 예제에서 5/7, 제출하면 68점으로 실패했었다.
응답 시작과 완료 시간은 millisecond 단위로 변환해서 계산했다.
👱♀️ 다른사람 풀이
# https://velog.io/@someh/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%B6%94%EC%84%9D-%ED%8A%B8%EB%9E%98%ED%94%BD
from datetime import datetime, timedelta
def compare(time, moment):
start = time
end = time + timedelta(milliseconds=999) # 시작시간과 끝시간을 포함하므로
if start >= moment[0] and start <= moment[1]:
return True
elif end >= moment[0] and end <= moment[1]:
return True
elif start <= moment[0] and end >= moment[1]:
return True
return False
def solution(lines): # lines : 응답완료시간 s와 처리시간 t
result = []
for line in lines:
temp = line.split(' ')
date = str(temp[0]) + " " + str(temp[1]) # 응답 완료 시간
if '.' in temp[2]:
delay = temp[2].split('.')
delay[1] = delay[1][0:-1] # s 제외하고 숫자만
else:
delay = list(temp[2][0:-1])
delay += ["0"]
end = datetime.fromisoformat(date)
start = end - timedelta(seconds=int(delay[0]), milliseconds=int(delay[1]) - 1)
result.append([start, end])
answers = []
for timelist in result: # 로그
for time in timelist: # 로그의 시작 시간 또는 종료 시간
answer = 0
for moment in result:
if compare(time, moment) == True:
answer += 1
answers.append(answer)
return max(answers)
요청량이 변하는 순간은 각 로그의 시작과 끝이다.
작업의 시작 시간과 끝나는 시간을 구해서 result에 담는다.
각 작업의 start와 end 각각에 대해서 1초간 요청이 들어왔는지 본다.
임의 시간부터 1초간 처리하는 요청의 최대 개수를 센다. 각각의 로그를 모든 로그의 start와 end 타임라인 안에 들어가는지 본다.
1. moment[0]이 start보다 작거나 같고, 끝나는 시간 moment[1]이 start보다 크거나 같을 때
2. moment[0]이 end보다 작거나 같고, 끝나는 시간 moment[1]이 end보다 크거나 같을 때
3. 시작 시간 moment[0]이 start보다 작거나 같고, 끝나는 시간 moment[1]이 end보다 크거나 같을 때
위의 세가지 경우에 초당 요청이 처리됨.
# 출처 : https://it-garden.tistory.com/m/408?category=857251
def checktr(time,li):
c=0
start=time
end=time+1000
for i in li:
if i[1] >= start and i[0] < end:
c += 1
return c
def solution(lines):
li=[]
r=1
for line in lines:
y,a,b=line.split() # 날짜, 시간, 처리시간
a=a.split(':') # 시간
b=float(b.replace('s',''))*1000 # millisecond로 변환
end=(int(a[0])*3600 + int(a[1])*60 + float(a[2]))*1000 # millisecond로 변환
start=end-b+1
li.append([start,end])
for i in li:
r=max(r,checktr(i[0],li),checktr(i[1],li))
return r
위 풀이와 알고리즘은 같다.
🙇♀️ 출처 : 프로그래머스
'coding test' 카테고리의 다른 글
[파이썬] 단속카메라 (0) | 2021.04.05 |
---|---|
[파이썬] 자물쇠와 열쇠 (0) | 2021.04.02 |
[파이썬, Java] 단어 변환 (0) | 2021.03.26 |
[파이썬] 디스크 컨트롤러 (0) | 2021.03.25 |
[파이썬, Java] 네트워크 (0) | 2021.03.24 |