[プログラマー]中秋節の流量


問題の説明
中秋節の流量
今年の秋夕(チュソク、陰暦8月15日)にシステム障害のない祝日を過ごすために、Apacheはサーバーの増設を悩んでいる.障害対応サーバーを増設するかどうかを決めるため、昨年秋夕(チュソク、陰暦8月15日)、9月15日にログデータを分析した後、1秒当たりの最大スループットを算出することにした.1秒あたりの最大スループットは、要求が応答を完了するかどうかにかかわらず、任意の時間から1秒(=1000ミリ秒)の要求を処理する最大数を意味します.
入力フォーマット
solution関数に渡されるlines配列はN(1≦N≦2000)個のログ文字列からなり、各ログ文字列は要求に対する応答完了時間Sと処理時間Tをスペースで区切っている.
応答完了時間Sは昨年秋夕2016年9月15日のみで、固定長2016-09-15 hh:mm:ss.sss形式で存在する.
処理時間Tは、0.1 s,0.312 s,2 sのように最大小数点の3番目のビットに記録され、後に秒単位を示すsが続く.
例えば、ログ文字列2016-09-1503:10:33.00 0.011 sは、「2016年9月15日午前3時10分33.00秒」から「2016年9月15日午前3時10分33.00秒」、「0.011秒」の間に処理されるリクエストを意味する.(処理時間は開始時間と終了時間を含む)
サーバ上のタイムアウト時間は3秒であるため、処理時間は0.001≦T≦3.000である.
lines配列は、応答完了時間Sを基準として昇順に配列されている.
出力フォーマット
solution関数は、ログデータ線アレイに対して毎秒最大スループットを返します.
I/O例
例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秒間処理した.
第2に、それは01:00:05.001~01:00:07.000で2秒処理される.
したがって、1番目のログ終了と2番目のログ開始の期間01:00:04.002~01:00:05.001秒で、最大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個であることがわかる.したがって、1秒当たりの最大スループットは7であり、同じ最大スループットを有する1秒セグメントが複数存在する可能性があるため、この問題では、区間ではなく個数のみが出力される.

初めての試み
import java.util.*;

class Solution {
    public int solution(String[] lines) {
        
        int answer = 0;
        
        // hh:mm:ss.sss (s)
        // 작업이 종료된 시간 : 걸린 시간 
        // a <= x <= b : 걸린 시간 T = (b-a-1)
        // 20:59:57.421
        // 0.351s
        // 57.421 - 0.351 + 0.001 = 20:59:57.071 부터 시작 
        
        // [구간] 내 해당하는 프로세스를 더한다.
        // [구간] : 작업 갯수의 변화가 생기면 구간이 바뀌는 것으로 한다. 
        // 1.0s 당 최대 거리량을 계산한다. 
        
        ArrayList<Integer> processStack = new ArrayList<>();
        
        String[] startDataRef = lines[0].split(" ");
        String startTimeRef = startDataRef[1]; // 첫 프로세스
        String deltaRef = startDataRef[2];
        deltaRef = startDataRef[2].substring(0, deltaRef.length()-1); // 끝 문자열 s 자른다. 
        
        int initSecondRef = Integer.parseInt(startTimeRef.split(":")[2]) - Integer.parseInt(deltaRef); // 첫 프로세스 시작 초 
        
        // 시간, 분이 바뀌는 조건문을 추가해야한다. 
        
        // 프로세스 끝난 시간에서 걸린 시간을 빼야 하는데, 모든 시간을 계산한 뒤 [프로세스 인덱스, 시작 시간, 걸린 시간] 으로 객체를 하나 생성합니다. 
        Queue<String> queue = new LinkedList<>(); // 
        
        int count = 1;
        
        for(String line : lines){
            
            // 1. 시작 기준은 맨 처음 시작되는 프로세스이다.
            // 2. 끝나는 지점이 1초 구간안에 있으면 Queue 에 집어넣는다.
            // 3. 그 다음 1초 구간에서 기존에 있던 line 이 있던 경우, 없는 경우 두 가지로 나눈다. 
            // 4. line 이 없으면 Queue 에서 제거한다. 
            // 5. line 이 존재하면 Queue 를 그대로 유지한다.
            // 6. Queue 를 그대로 유지한 채, 새롭게 시작되는 프로세스가 있으면 Queue 에 추가시킨다.
            
            String[] startData = line.split(" ");
            String startTime = startData[1]; // 첫 프로세스
            String delta1 = startData[2];
            delta1 = startData[2].substring(0, delta1.length()-1); // 끝 문자열 s 자른다. 
            int initSecond = Integer.parseInt(startTime.split(":")[2]) - Integer.parseInt(delta1); // 첫 프로세스 시작 초 
            
            int min = Integer.parseInt(startTime.split(":")[1]);
            int hour = Integer.parseInt(startTime.split(":")[0]);
            
            if(initSecondRef + 1 > initSecond){ // 시작시간 + 1초 안에 들어와 있을 경우
                count++;
            } else { // 범위에서 벗어났을 경우 더 이상 해당 범위 안에 새롭게 시작되는 프로세스가 없으므로 다음 +1초로 넘어간다. 
                processStack.add(count);
                count = 1;
            }
            
            answer = count;
                
        }
        return answer;
    }
}
初めての試みのハイライト
  • は起点、終点を基準にすべきだと思います.
  • 始点と終点がペアになるべきと考えられているので、Mapインタフェースを使うべきです.
  • 判断
  • の区間は1秒なので、最初のプロセス開始の起点を0,+1にすれば良いのではないでしょうか?
  • 題では、終点と所要時間しか与えられていないので、起点を求めるには減算します.
  • 開始時間、時間+1秒この区間で開始するプロセスがあればcount++が可能です.
  • 1秒を基準として、最大値を更新し、最大値を求める.
  • 2回目の試み
  • TreeMapと宣言された後、開始時間、終了時間が保存されます.
  • Stringと宣言された時間を計算可能なIntegerタイプに変換する必要があります.
  • しかし、考えてみれば、キー値が存在する場合、mapインタフェースは追加できず、置換するしかありません.
  • は同時にプロセスを開始します.エンドポイントが異なると、エラーが発生するケースが1つ失われます.
  • ですのでbegin,endはそれぞれArrayListとして保存すべきだと思います.
  • だから実施する.
  • で与えられたプロセス完了時間から所要時間を減算し、開始時間を基準に計算するのが便利である.
  • 合計時間.時間+分+秒を求め,Integer形式で求める.