잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→

현록의 기록저장소

[Lv3] 추석 트래픽 본문

Problem Solving/programmers

[Lv3] 추석 트래픽

현록 2021. 4. 21. 18:36

programmers.co.kr/learn/courses/30/lessons/17676

 

코딩테스트 연습 - [1차] 추석 트래픽

입력: [ "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-1

programmers.co.kr

문제 설명

추석 트래픽

이번 추석에도 시스템 장애가 없는 명절을 보내고 싶은 어피치는 서버를 증설해야 할지 고민이다.

장애 대비용 서버 증설 여부를 결정하기 위해

작년 추석 기간인 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:04.002 ~ 01:00:05.001 1초 동안 최대 2개가 된다.
  • 두 번째 로그는 01:00:05.001 ~ 01:00:07.000에서 2초 동안 처리된다.

예제3

  • 입력: ["2016-09-15 20:59:57.421 0.351s","2016-09-15 20:59:58.299 0.8s","2016-09-15 20:59:59.591 1.412s","2016-09-15 21:00:00.741 1.581s","2016-09-15 21:00:00.966 0.381s",]
  • "2016-09-15 21:00:02.066 2.62s"
  • "2016-09-15 21:00:00.748 2.31s",
  • "2016-09-15 21:00:00.464 1.466s",
  • "2016-09-15 20:59:58.688 1.041s",
  • "2016-09-15 20:59:58.233 1.181s",
  • 출력: 7
  • 설명: 아래 타임라인 그림에서 빨간색으로 표시된 1초 각 구간의 처리량을 구해보면 (1)은 4개, (2)는 7개, (3)는 2개임을 알 수 있다. 따라서 초당 최대 처리량은 7이 되며, 동일한 최대 처리량을 갖는 1초 구간은 여러 개 존재할 수 있으므로 이 문제에서는 구간이 아닌 개수만 출력한다.

 


import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Solution {
    public int[] timestampToNumbers(String timestamp) {
        int[] result = new int[2];
        int hour = (timestamp.charAt(11) - '0') * 10 + (timestamp.charAt(12) - '0');
        int min = (timestamp.charAt(14) - '0') * 10 + (timestamp.charAt(15) - '0');
        int millsec = (timestamp.charAt(17) - '0') * 10000 + (timestamp.charAt(18) - '0') * 1000 + (timestamp.charAt(20) - '0') * 100 + (timestamp.charAt(21) - '0') * 10  + (timestamp.charAt(22) - '0');
        Matcher matcher = Pattern.compile("(\\d+\\.\\d{1,3}s)|(\\d+s)").matcher(timestamp);
        matcher.find();
        String work = matcher.group();
        int indexDot = work.indexOf('.');
        int timeWork = 0;
        if (indexDot == -1) {
            timeWork = Integer.parseInt(work.substring(0, work.length() - 1)) * 1000;
        } else {
            timeWork = Integer.parseInt(work.substring(0, indexDot)) * 1000;
            timeWork += Integer.parseInt(work.substring(indexDot + 1, work.length() - 1));
        }
        result[1] = millsec + min * 60000 + hour * 3600000;
        result[0] = result[1] - timeWork + 1;
        return result;
    }

    public String NumberToTimestamp(int number) {
        int hour = number / 3600000;
        number %= 3600000;
        int min = number / 60000;
        number %= 60000;
        int sec = number / 1000;
        number %= 1000;
        return String.format("%02d:%02d:%02d.%03d", hour, min, sec, number);
    }

    public int solution(String[] lines) {
        Comparator<int[]> comparator = new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[0] == o2[0]) {
                    return o1[1] - o2[1];
                } else {
                    return o1[0] - o2[0];
                }
            }
        };
        int[][] logs = new int[lines.length][];
        for (int i = 0; i < lines.length; ++i) {
            logs[i] = timestampToNumbers(lines[i]);
        }
        Arrays.sort(logs, comparator);
//        System.out.println("----------");
//        for (int i = 0; i < logs.length; ++i) {
//            System.out.println(String.format("%s ~ %s", NumberToTimestamp(logs[i][0]), NumberToTimestamp(logs[i][1])));
//        }
//        System.out.println("----------");
        int answer = 0;
        int timeStart = logs[0][0];
        int timeComplete = 0;
        for (int i = 0; i < logs.length; ++i) {
            if (logs[i][1] > timeComplete) {
                timeComplete = logs[i][1];
            }
        }
        if (timeComplete < timeStart + 1000) {
            timeComplete = timeStart + 1000;
        }
        HashSet<Integer> set = new HashSet<>(logs.length);
        int indexNext = 0;
        while (true) {
            if (set.isEmpty()) {
                timeStart = logs[indexNext][0];
                set.add(indexNext);
                ++indexNext;
                while (indexNext < logs.length) {
                    if (logs[indexNext][0] >= timeStart && logs[indexNext][0] < timeStart + 1000) {
                        set.add(indexNext);
                        ++indexNext;
                    } else {
                        break;
                    }
                }
            } else {
                int startNext = logs[indexNext][0];
                int endFirst = Integer.MAX_VALUE;
                for (Integer index : set) {
                    if (logs[index][1] < endFirst) {
                        endFirst = logs[index][1];
                    }
                }
                if (endFirst <= startNext - 1000) {
                    int[] array = set.stream().mapToInt(Integer::intValue).toArray();
                    for (int i = 0; i < array.length; ++i) {
                        if (logs[array[i]][1] == endFirst) {
                            set.remove(array[i]);
                        }
                    }
                    timeStart = endFirst;
                }
                if (endFirst >= startNext - 1000) {
                    while (indexNext < logs.length) {
                        if (logs[indexNext][0] == startNext) {
                            set.add(indexNext);
                            ++indexNext;
                        } else {
                            break;
                        }
                    }
                    timeStart = startNext - 1000;
                }
            }
            if (set.size() > answer) {
                answer = set.size();
            }
            if (indexNext >= logs.length) {
                break;
            }
        }
//            System.out.println(String.format("[%s ~ %s]: %d", NumberToTimestamp(timeStart), NumberToTimestamp(timeStart + 1000), count));
        return answer;
    }
}

 

 

'Problem Solving > programmers' 카테고리의 다른 글

[Lv3] 기둥과 보 설치  (0) 2021.04.22
[Lv3] 불량 사용자  (0) 2021.04.22
[Lv3] 순위  (0) 2021.04.20
[Lv3] 셔틀버스  (0) 2021.04.20
[Lv3] 입국심사  (0) 2021.04.19
Comments

잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→