코딩테스트/2018 블라인드 코딩 테스트

[2018 KAKAO BLIND RECRUITMENT] [1차] 추석 트래픽 for JAVA

냠냠:) 2020. 3. 27. 21:10

[문제 설명]

추석 트래픽

이번 추석에도 시스템 장애가 없는 명절을 보내고 싶은 어피치는 서버를 증설해야 할지 고민이다. 장애 대비용 서버 증설 여부를 결정하기 위해 작년 추석 기간인 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초 구간 동안 처리되는 로그를 확인했다. 구간을 나눠야 했기에 String의 split함수를 사용했고 소수점 부분 처리 때문에 Double형 변수와 ParseDouble을 사용했다. 두 번째 for문을 보면 if문이 두 개가 있는데 각자 시작부분, 끝부분을 기준으로 1초 동안에 다른 로그가 있는지 확인 한 것이다. 다른 로그와의 비교는 다른 로그의 끝부분이 1초구간의 시작점보다 크고 로그 시작부분이 1초구간 끝 부분 보다 작으면 그 "시점"에서 처리된 것을 의미한다. 부족하지만 아래 직접 그린 그림을 보고 이해가 됐으면 좋겠다.

if(startTemp <= end[j] && start[j] <= startsSection)을 설명한 그림(1초구간 밑 3가지 상황을 모두 검출해 낼 수 있는 if문이다.

[코드]

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
43
public static int solution(String[] lines) {
        double[] start = new double[lines.length];                    //시작시간
        double[] end = new double[lines.length];                    //끝난시간
        for(int i = 0; i < lines.length; i++) {                        
            String responTime = lines[i].split(" ")[1];                //초단위로 나누기위한 split
            String handleTime = lines[i].split(" ")[2];                //처리 시간    
            
            double endTime = 0.0;
            double startTime = 0.0;
            endTime += 3600.0 * Double.parseDouble(responTime.split(":")[0]);    //시, 분을 초단위로 변환
            endTime += 60.0  * Double.parseDouble(responTime.split(":")[1]);
            endTime += Double.parseDouble(responTime.split(":")[2]);
            
            startTime = Math.round((endTime - Double.parseDouble(handleTime.replace("s"""))+0.001)*1000)/1000.0//s를 빼고 응답시간을 빼주면 시작시간
            
            end[i] = endTime;
            start[i] = startTime;
        
        }
          int answer = 0
          for(int i = 0; i < lines.length; i++) {
             double startTemp = start[i];
             double endTemp = end[i];
             int startCount = 0;                    //로그 start 지점에서 1초안에 있는 로그 수
             int endCount = 0;                        //로그 end 시점에서 1초안에 있는 로그 수
             for(int j = 0; j < lines.length; j++) {
                 double startsSection = Math.round((startTemp+0.999)*1000)/1000.0;     //로그 시작시점 기준으로 1초뒤 시간
                 double endSection = Math.round((endTemp+0.999)*1000)/1000.0;         //로그 끝 시점 기준으로 1초뒤 시간
                 if(startTemp <= end[j] && start[j] <= startsSection) {                 //임의 로그의 시작 부분과 끝부분이 다른 로그의 끝 부분 보다 작고 시작 부분보다 크다면, 
                     startCount++;
                 }
                 if(endTemp <= end[j] && start[j] <= endSection) {                    //로그의 end부분에서도 똑같이 실행
                     endCount++;
                 }
             }
             if(answer < Math.max(startCount, endCount)) {                            //최대 처리량만 구하기.
                 answer = Math.max(startCount, endCount);
             }
          }
          
        return answer;
        
    }
cs

프로그래머스 테스트 케이스 통과

느낀 점: 처음 프로그래머스 level 3에 들어와서 문제가 많이 어려울까 긴장을 많이 했었다. 역시나 실제로 문제를 접하니 많이 어려웠다.. 중간에 다른 사람 것을 보고 응용해볼까라는 생각도 들었지만 혼자 힘으로 끝까지 해보자는 생각이 계속 들어서 결국 혼자 마무리를 하게 되었다. 생각보다 문제를 어떻게 해결할지의 생각의 시간이 길었다. 설계가 끝나고 문제를 풀었을 때는 도대체 어느 부분을 기준으로 로그를 잡아야 되는지 도무지 생각이 안 났었다. 근데 역시 사람은 쉴 때 답을 찾는다고 했었는가. 쉬려고 누워서 유튜브를 보다가 갑자기 풀이 방법이 생각나서 앉아서 조금 코딩하니 풀렸다. 

 

**double형으로 계산을 하니 0.00000001 이런 식으로 많이 나왔다. 이럴 땐 Math.round(double변수 * 1000)/1000.0을 하면 없어진다는 것을 배웠다. 물론 다른 방법도 있지만 가장 쉬운 것 같다. 곱하는 숫자(1000)의 기준은 소수점 몇 번째에서 반올림할지에 따라 달라진다.

 

**생각을 쓰게 한 부분 : 시간 처리 부분(초 단위), 로그 검출 기준점 잡기, 소수점 자리 처리 부분

 

**피드백은 언제나 환영입니다!!

반응형