티스토리 뷰

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

# 핵심

1. 날짜 포맷을 숫자로 변환하기

2. 구간 체크

 

 

# 날짜 포맷을 숫자로 변환하는 방법

1. String을 ":" 기준으로 split 한 다음 각각 더하기

    public long getMilSecByString(String time) {
        long val = 0;
        String[] split = time.split(":");
        val += (Long.parseLong(split[0]) * 60 * 60); // 시
        val += (Long.parseLong(split[1]) * 60); // 분
        val *= 1000; // 밀리초 단위로 변환하기 위해
        val += (Double.parseDouble(split[2]) * 1000); // 초 (1초 = 1000밀리초)

        return val;
    }

 

그냥 제일 기본적으로 시/분/초 를 각각 단위에 맞게 잘 더해서 사용하는 방식

기본적인 초 단위가 아니라 밀리초 단위를 사용하기 위해 1000을 곱해줬다는 것에 유의해야 한다.

(소숫점을 없애주기 위함.)

 

근데.. 그냥 double을 사용하면 안되는걸까?

-> double을 사용하려고 하면 부동소수점 오차 때문에 정확하지 않은 결과가 나올 수 있다!

 

** (정확한 소숫점 연산을 위해서는 BigDecimal 클래스를 사용해야 한다) **

 

 

2. SimpleDateFormat을 사용해서 변환하기

String[] split = line.split(" ");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
try {
    long time = sdf.parse(split[0] + " " + split[1]).getTime();
    System.out.println(time);
} catch (ParseException e) {
    System.out.println("Error");
}

SimpleDateFormat을 이용해서 포맷을 지정한 다음

-> parse 메서드를 이용해서 String을 Date 타입으로 변환

-> getTime 메서드를 이용하면 밀리초 단위의 시간을 얻을 수 있다..

 

parse 메서드를 사용하면 checked exception 처리를 필수로 해줘야 해서 좀 불편한 점이 있다.

이건 몰라도 문제는 없는데 알면 좀 좋고 딱 그정도?

 

 

# 구간 찾기

구간 체크 하는게 생각보다 힘들었다. 내 머리가 마치 돌대가리가 된 것 같았다...

 

일단, 대체 어떻게 최대한 많은 로그 작업을 처리하는 구간을 구하는가?? 를 떠올리는 것 부터가 어려웠다..1초 길이의 구간 내에 최대한 많은 작업이 들어오는 구간을 찾아내야 한다.

 

결론부터 말하자면 작업의 시작점 or 끝점을 기준으로 잡아서 1초의 구간을 만들면 된다.

왜냐하면 동시 처리 요청되는 작업의 개수는 작업의 시작점 / 끝점에서만 변경되기 때문이다. 이를 다른곳에서는 변경점이 시작/끝점이기 때문이라고 표현 하더라.

 

끝점을 기준으로 뒤에 1초의 구간을 만들어서 작업을 센다고 가정하면 아래의 그림과 같이 될 수 있다.

 

구간에 포함되는 모든 경우의 수 (총 4가지)

 

구간에 포함되는 경우의 수는 총 4가지가 있다. 

해당 작업들의 공통 특징을 살펴보면, 작업의 시작 시간은 end + 1초 이전이면서, 작업의 종료 시간은 end초 이상이라는 것을 알 수 있다.

* (기준점이 되는 작업 자신도 같이 포함된다) --> 위 사진에서 최대 초당 처리량은 4가 아니라 5다 5

        for(int i = 0; i < jobList.size(); i++) {
            int cnt = 0;
            long end = jobList.get(i).endTime;
            for (Job job : jobList) {
                if(job.startTime < end + 1000 && job.endTime >= end) cnt++;
            }
            ans = Math.max(ans, cnt);
        }

 

위 그림을 코드로 옮기면 아래와 같이 된다.

그리고 부등호가 < 이냐 <= 이냐,, > 이냐 >= 이냐에 유의하자.. 진짜 사람 돌아버린다

 

작업의 시작 시간은 작업의 종료 시간에서 작업 처리 시간을 빼서 구하면 된다.

여기서 또 주의해야 하는 것이,  "처리시간은 시작시간과 끝시간을 포함" 한다.

 

1 이상 10 이하인 개수를 구하기 위해 10 - 1 + 1 = 10개 해주는거랑 똑같다.

"종료 시간 - 처리 시간 + 1" 을 해주면 된다

long end = getMilSecByString(splits[1]);
long start = end - (long) (Double.parseDouble(splits[2].replace("s", "")) * 1000) + 1;

 

 

그렇게 해서 전체 코드를 보면 아래와 같이 된다

 

# 통과 코드

import java.util.*;

class Solution {

    public long getMilSecByString(String time) {
        long val = 0;
        String[] split = time.split(":");
        val += (Long.parseLong(split[0]) * 60 * 60); // 시
        val += (Long.parseLong(split[1]) * 60); // 분
        val *= 1000; // 밀리초 단위로 변환하기 위해
        val += (Double.parseDouble(split[2]) * 1000); // 초 (1초 = 1000밀리초)

        return val;
    }

    private static class Job {
        long startTime;
        long endTime;

        public Job(long startTime, long endTime) {
            this.startTime = startTime;
            this.endTime = endTime;
        }
    }

    public int solution(String[] lines) {
        List<Job> jobList = new ArrayList<>();
        for (String line : lines) {
            String[] splits = line.split(" ");
            long end = getMilSecByString(splits[1]);
            long start = end - (long) (Double.parseDouble(splits[2].replace("s", "")) * 1000) + 1;

            Job job = new Job(start, end);
            jobList.add(job);
        }

        int ans = 1;
        for(int i = 0; i < jobList.size(); i++) {
            int cnt = 0;
            long end = jobList.get(i).endTime;
            for (Job job : jobList) {
                if(job.startTime < end + 1000 && job.endTime >= end) cnt++;
            }
            ans = Math.max(ans, cnt);
        }
        System.out.println(ans);
        return ans;
    }
}

 

왜이렇게 머리가 안돌아가는지 모르겠다. 풀면서 현타가 좀 왔다.

복습만이 답일까

블로그 포스팅이라도 자세히 써야겠다..

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함