시간 다루기

1. 문제

 

이벤트 시작 날짜와 이벤트가 끝나는 날짜, 고객의 접속 기록이 주어진다.

 

모든 날짜는 mm/dd 형태로 주어지는데 이벤트 시작 날짜는 mm/dd day 형태로 주어진다.

 

day는 'MON','TUE','WED','THU','FRI','SAT','SUN' 중 하나로 주어진다.

 

고객의 접속 기록은 시작 날짜와 끝나는 날짜 사이에서 접속한 날짜를 리스트 형태로 주어진다.

 

2월은 항상 28일로 끝난다고 가정한다.

 

날짜는 01/01부터 12/31까지 주어지고 시작 날짜가 끝나는 날짜보다 늦는다던지 형식에 맞지 않는 경우는 주어지지 않는다

 

이 때 고객이 평일에 연속해서 접속한 기록의 최대 일수를 구한다면?

 

예를 들어 24일이 목요일 일때, 24,25,26,28,29,31 접속했다고 가정하자. 

 

일요일인 27일은 접속하지 않았지만 일요일은 평일이 아니라서 24,25,26,28까지 연속해서 접속했다고 하여 총 3일 평일 연속해서 접속했다.

 

마찬가지로 24,25,28,29,31 접속했다면 토일인 26,27은 접속하지 않았지만 24,25,28 목금월 3일 평일 연속해서 접속했다고 하자.

 

 

2. 풀이?

 

1월부터 12월까지 총 몇일 존재하는지 last_day라는 dict에 집어넣고

 

인덱스와 요일을 대응시키는 day_of_week라는 dict를 만들었다

 

split()을 이용해서 mon, day 필요한 정보를 뽑아옴

 

def solution(start_date, end_date, login_dates):

    last_day = {1:31,2:28,3:31,4:30,5:31,6:30,7:31,
                   8:31,9:30,10:31,11:30,12:31}

    day_of_week = {0:'SUN',1:'MON',2:'TUE',3:'WED',4:'THU',5:'FRI',6:'SAT'}

    sorted_login_dates = sorted(login_dates)

    start_mon,start_day = start_date.split()[0].split('/')

    end_mon,end_day = end_date.split('/')

    start_day_of_week = start_date.split()[1]

 

login 기록이 정렬되어 있지 않은데 sorted()로 정렬하면 비록 문자열 리스트더라도 신기하게 정렬해서 나온다

 

a = ['05/26','05/25','05/27','05/10','05/11','05/23','05/22','05/21','05/06','05/09','05/07','05/08']

print(a)

print(sorted(a))

['05/26', '05/25', '05/27', '05/10', '05/11', '05/23', '05/22', '05/21', '05/06', '05/09', '05/07', '05/08']
['05/06', '05/07', '05/08', '05/09', '05/10', '05/11', '05/21', '05/22', '05/23', '05/25', '05/26', '05/27']

 

이런건 외우는게 아니라 일단 sorted()해서 실제로 정렬이 되는지 print로 확인해보면 되는거거든 아주 잘했고

 

    ## find day_list from start_date to end_date

    day_list = []

    day = int(start_day)

    for mon in range(int(start_mon),int(end_mon)+1):

        while 1:

            if last_day[mon]+1 == day:

                day = 1

                break

            if mon < 10:

                str_mon = str(0)+str(mon)

            else:

                str_mon = str(mon)

            if day < 10:

                str_day = str(0)+str(day)

            else:

                str_day = str(day)

            day_list.append(str_mon+'/'+str_day)

            day += 1

 

시작 날짜인 start_date부터 끝 날짜인 end_date까지 일정표를 만들고 싶은거

 

5월 27일부터 6월 14일까지 05/27,05/28,05/29,05/30,05/31,06/01,06/02,06/03,06/04,06/05,06/06,06/07,06/08,06/09,06/10,06.11,06/12,06/13,06/14를 만들고

 

각 날짜는 무슨 요일인지 dict로 만들면 좋을것 같다고 생각을 했음

 

start_mon이랑 end_mon이 문자열이라 int로 바꿔서 for문을 도는데 month마다 총 일수가 다르니까 미리 만들어 놓은 last_day dict를 이용한다면

 

last_day[mon]으로 month의 마지막 일이 언제인지 알 수 있지

 

while을 이용해서 day를 1씩 증가시켜나가면서 day_list에 집어넣을건데

 

증가하다가 현재 mon의 마지막 일인 last_day[mon]보다 1 큰 last_day[mon]+1이 된다면 day=1로 처음부터 시작하면서 break로 while문을 탈출해서 새로운 mon을 가져오는거고

 

start_date부터 end_date까지 mm/dd 형태로 day_list에 저장을 해둘거임

 

근데 문자열 예를 들어 '07'을 int로 바꾸면 7이 되는데 10보다 작은 경우는 앞에 '0'을 붙여서 '07'로 다시 복구시켜서 mm/dd 형태로 저장시킬거임

 

    ## find day in login_date

    day_of_login = {}

    ind = 0

    for key,day in day_of_week.items():

        if day == start_day_of_week:

            ind = key

            break

    for day in day_list:

        if ind == 7:

            ind = 0

        day_of_login[day] = day_of_week[ind]

        ind += 1

 

그 다음에 start_date부터 end_date까지 존재하는 날짜들이 무슨 요일인지 알아야 평일인지 주말인지 검사를 할테니까

 

앞에서 만들어놓은 day_of_week dict를 이용해서 무슨 요일인지 검사하고 새로운 dict를 만들거임

 

첫 시작 날짜 start_date의 요일을 이용해서 시작 key가 무엇인지 찾고나서

 

day_list에서 하나씩 뽑아 day를 가져온 다음에 day를 key로 요일을 value로 하는 day_of_login이라는 dict를 만든다

 

시작 key부터 1씩 증가시키는데 key가 7이 되는 순간 0으로 바꾸면 일,월,화,수,목,금,토를 반복할 수 있겠지

 

시작 key가 4이면 현재 목요일인데 key가 1씩 증가하면 목,금,토인 key=6까지 오는데 여기서 1 증가하면 key=7인데 key=7의 value는 day_of_week에 존재하지 않아서 key=0으로 만들어야 일요일부터 다시 시작 가능

 

 

    ## find max sucessive weekday

    suc_day = 0

    max_day = 0

    weekday_list = ['MON','TUE','WED','THU','FRI']

    weekend_list = ['SUN','SAT']

    for day in day_list:

        if day in sorted_login_dates:

            if day_of_login[day] in weekday_list:

                suc_day += 1

            else:

                pass

        else:

            if day_of_login[day] in weekend_list:

                continue

            else:

                if max_day <= suc_day:

                    max_day = suc_day

            suc_day = 0

    return max_day

 

그 다음에 연속해서 평일 접속한 최대 일수를 찾을건데 역으로 생각을 해서

 

start_date부터 end_date까지 존재하는 일을 day_list에 저장해두었으니까 day_list에서 하나씩 뺸 다음에

 

sorted_login_date에 존재하는지 존재하지 않는지 검사를 해보는거임

 

login date에 존재한다면, 실제로 접속한 날이니까 이게 평일인지 주말인지 검사를 해야함

 

평일이면 연속 접속 기록이 시작이 되니까 suc_day에 1을 증가시켜나감

 

접속을 했지만 주말이면 평일 접속 기록의 날짜 수에 세지 않으니까 그냥 pass만 함

 

근데 이제 day_list에서 하나씩 뺀 day가 login date에 존재하지 않는다면 연속 접속 기록이 꺠지는 가능성이 생기니까

 

실제로 그런지 검사를 해봐야하는데 이 day가 주말이라면 평일 연속 접속 기록이 꺠지지 않는다는 문제 조건이 있었어서 continue로 for문 1번을 넘긴다

 

이런 경우는 수,목,금까지 접속 했는데 토,일은 접속 기록이 없었어... 근데 day_list의 day가 바로 이 토,일인거지

 

근데 day가 login date에 존재하지 않는데 주말까지도 아니라면 그것이야말로 연속 접속 기록이 깨진거니까

 

현재까지 계산한 suc_day와 max_day를 비교해서 최댓값이면 max_day에 저장을 해두는거지

 

접속 기록이 깨졌으니까 suc_day=0으로 하는거고

 

 

3. 되돌아보기

 

헷갈릴수 있는데 논리적으로 상당히 잘 했음

 

정답인지는 모르겠지만 기본 테스트 케이스는 다 맞췄으니까 훌륭

 

더 효율적이게 만들 여지는 있을 것 같지만 시간이 없었으니까 아쉽긴한데

 

 

TAGS.

Comments