# [프로그래머스] Lv 3. [1차] 추석 트래픽

문제 : [1차] 추석 트래픽 (opens new window)

# 문제 설명

이번 추석에도 시스템 장애가 없는 명절을 보내고 싶은 어피치는 서버를 증설해야 할지 고민이다.
장애 대비용 서버 증설 여부를 결정하기 위해 작년 추석 기간인 9월 15일 로그 데이터를 분석한 후 초당 최대 처리량을 계산해보기로 했다.
초당 최대 처리량은 요청의 응답 완료 여부에 관계없이 임의 시간부터 1초(=1,000밀리초)간 처리하는 요청의 최대 개수를 의미한다.

# 입력형식

  • solution 함수에 전달되는 lines 배열은 N(1N2,000)N(1 \leq N \leq 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.001T3.0000.001 \leq T \leq 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

# 예제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

# 문제 풀이

  • 제일 단순하게 드는 생각은 0.001초 단위로 0.001~1.000, 0.002~1.001, 0.003~1.002 이런식으로 구간을 만들어서 for문을 돌리는 것을 생각했으나 너무 비효율적이다.
  • 특정 로그가 종료되면서 시작되는 1초 구간의 로그 개수를 확인해서 가장 많이 나온 구간의 로그 개수를 return한다.

# 코드 구현

  • 각각 로그의 시작시간과 끝시간, 처리시간을 실수(double)로 변환하여 저장한다.
  • 각각 로그의 끝시간 + 1 보다 시작시간이 빠르면서 각각 로그의 끝시간과 같거나 늦게 끝난 로그들의 수를 카운트한다.
  • 가장 카운트가 많은 값을 return한다.

# Java

class Solution {
  public int solution(String[] lines) {
      int answer = 0;
      int count = lines.length;
      
      double[] durations = new double[count];  // 처리시간 배열
      double[] endTimes = new double[count];   // 끝시간 배열
      double[] startTimes = new double[count]; // 시작시간 배열

      for(int i=0; i<count; i++) {
          String[] lineItems = lines[i].split(" ");

          // s제거하여 (0.000s -> 0.000) double로 변환하여 배열에 저장
          durations[i] = Double.parseDouble(lineItems[2].replace("s",""));

          String[] times = lineItems[1].split("[:|.]");
          
          // 계산 편의를 위해 시 * 3600 + 분 * 60 + 초 + 밀리조로 시작시간을 배열에 저장한다.
          endTimes[i] = Double.parseDouble(times[0]) * 3600
                      + Double.parseDouble(times[1]) * 60
                      + Double.parseDouble(times[2])
                      + Double.parseDouble(times[3]) / 1000;
          // 처리시간은 시작시간과 끝시간을 포함하고 있으므로
          // 끝시간에서 처리시간을 뺀 후, 0.001초를 더해준다.
          startTimes[i] = endTimes[i] - durations[i] + .001;
      }

      for(int i=0; i<count; i++) {
          int sameTimeCount = 0;
          for(int j=0; j<count; j++) {
              // 끝시간~끝시간+1안에 다른 로그가 겹치면 카운트 추가
              if(endTimes[i] + 1 > startTimes[j] && endTimes[i] <= endTimes[j]) {
                  sameTimeCount++;
              }
          }
          if(sameTimeCount > answer) {
              answer = sameTimeCount;
          }
      }
      return answer;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42