프로그래머스 개인정보 수집 유효기간 2가지 풀이

고봉진·2023년 3월 14일
0

TIL/코딩테스트

목록 보기
14/27

요구사항 그대로 구현하기

from collections import defaultdict

# 1번, 17번
def solution(today, terms, privacies):
    terms_dict = defaultdict(int)
    for idx, term in enumerate(terms):
        key, val = term.split()
        terms_dict[key] = int(val)

    result = []
    for idx, val in enumerate(privacies):
        date, term = val.split()
        date = list(map(int, date.split('.')))
        date[1] += terms_dict[term]
        date[0] += (date[1] - 1) // 12
        date[1] -= ((date[1] - 1) // 12) * 12
        date = '.'.join(map(lambda x: str(x).zfill(2), date))
        if date <= today:
            result.append(idx+1)
        
    return sorted(result)

if __name__ == '__main__':
    cases = [
        ["2022.12.08", ["A 6"], ["2022.06.08 A"]],
        ["2021.12.08", ["A 18"], ["2020.06.08 A"]],
    ]

    for c in cases:
        print(solution(*c))
  1. term에서 제시하는 기간을 O(1)로 호출할 수 있도록 terms_dict를 만든다. collections 모듈의 defaultdict를 활용한다. 키가 존재하는지 확인할 필요 없이 바로 추가할 수 있게 해주는 함수이다.
  2. privacies를 순회하며 날짜 계산을 실시한다. 달에 해당하는 date[1]term으로 호출한 기간을 더해주고, 12를 초과할 경우 연도에 해당하는 date[0]에 더해준다.
    • (date[1] - 1) // 12 : 13일 경우 date[0]에 1이 더해져야 하지만 12일 경우 그대로여야 한다.
    • 12인데 연도를 더하고 월에 12를 빼버린다면, 위의 테스트 케이스에서 잘못된 답이 나올 것이다.
  3. 마찬가지로 연도를 올렸다면, 계산한 만큼에 12를 곱한 값을 빼서 계산한다.
  4. 연월일을 합치고, 오늘 날짜와 비교하여 만일 날짜가 오늘보다 같거나 작으면, 즉, 오늘부로 파기해야 한다면 인덱스에 1을 더하여 결과값에 추가한다.

product의 인덱스 활용

from collections import defaultdict
from itertools import product

dates_dict = {
    '.'.join(date): idx for idx, date in enumerate(
        product(
            [str(l) for l in range(2000, 2032)],
            [str(m).zfill(2) for m in range(1, 13)],
            [str(n).zfill(2) for n in range(1, 29)]
        )
    )
}

# 10, 12, 15, 18, 20
def solution(today, terms, privacies):
    # terms_dict = {'A': 6, 'B': 12, 'C': 3}
    terms_dict = defaultdict(int)
    for term in terms:
        key, val = term.split()
        terms_dict[key] = int(val)

    privacies_dict = defaultdict(list)
    for idx, term in enumerate(privacies):
        privacies_dict[term].append(idx+1)

    idx_today = dates_dict[today]    
    
    answer = []
    for prv in set(privacies):
        date, term = prv.split()
        if dates_dict[date] + 28 * terms_dict[term] <= idx_today:
            answer += privacies_dict[prv]

    return sorted(answer)

if __name__ == '__main__':
    cases = [
        ["2022.12.08", ["A 6"], ["2022.06.08 A", "2022.06.08 A"]],
        ["2021.12.08", ["A 18"], ["2020.06.08 A", "2020.06.08 A"]],
    ]

    for c in cases:
        print(solution(*c))
  1. itertools 모듈의 product 함수를 활용해, 2000년부터 2022년 12월 + 100개월까지 모든 날짜에 인덱스를 구하고, O(1)로 접근할 수 있도록 dictionary로 만든다.
  2. 위와 마찬가지로 terms_dict를 구비하고,
  3. privacies를 순회하며 각 키마다 마련된 리스트에 인덱스+1을 추가한다. 중복된 privacies 값이 있을 수 있으므로 리스트로 여러 인덱스를 가질 수 있게 했다.
    • 역시 빠르게 접근할 수 있도록 딕셔너리로 만들어, 한번만 접근하고도 같은 값을 가진 privacies의 모든 인덱스를 한번에 추가할 수 있게 했다. 아래 answer += privacies_dict[prv]에서 구현했다.
  4. 위와 같이 한번에 모든 인덱스를 가져올 수 있으므로 이번에는 set(privacies)를 순회한다. 각 날짜의 인덱스에 terms_dict에서 요구하는 달 수에 28일을 곱하여 언제까지 보관할 수 있는지에 대한 인덱스를 구한다. 그 값이 today의 인덱스보다 같거나 작으면, 즉 오늘부로 파기해야 한다면, answer에 그 케이스에 해당하는 모든 인덱스를 추가하고 정렬하여 반환한다.

Caveat

1, 17번이 틀린다면, 개월 수를 더하고 연도를 계산할 때 달이 0이 되는 경우를 확인해보고 10, 12, 15, 18, 20번이 틀린다면 중복된 값들 처리가 어떻게 되는지 확인해볼 것

profile
이토록 멋진 휴식!

0개의 댓글