시간 다루기
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. 되돌아보기
헷갈릴수 있는데 논리적으로 상당히 잘 했음
정답인지는 모르겠지만 기본 테스트 케이스는 다 맞췄으니까 훌륭
더 효율적이게 만들 여지는 있을 것 같지만 시간이 없었으니까 아쉽긴한데
'알고리즘 > 알고리즘 일반' 카테고리의 다른 글
수학 공식을 활용한 알고리즘 (0) | 2021.11.25 |
---|---|
탐욕법 활용 기초편 (0) | 2021.11.23 |
체스판에서 정사각형의 개수 (0) | 2021.11.22 |
문자열 다룰 때 필수적으로 갖춰야할 스킬들 (0) | 2021.11.21 |
완전히 탐색해야할때는.. (0) | 2021.11.21 |