Python Programming/[Programmers] Algorithm

[프로그래머스] 개인정보 수집 유효기간 Python 풀이

간토끼 2023. 10. 12. 16:39
728x90

# 해당 포스팅은 이제 막 알고리즘 공부를 시작한 초보 수준에서 작성했음을 이해해주시고, 비난보다는 따뜻한 조언을 부탁드립니다.


안녕하십니까, 간토끼입니다.

오늘은 프로그래머스(Programmers) 개인정보 수집 유효기간 문제에 대해 다뤄보겠습니다.

2023 카카오 블라인드 채용 코딩테스트 문제(Lv. 1 수준)입니다.

1. 문제 링크

https://school.programmers.co.kr/learn/courses/30/lessons/150370

 

프로그래머스

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

programmers.co.kr

고객의 약관 동의를 얻어서 고객의 개인정보를 다양하게 수집하고 있으며, 이 각각의 개인정보는 약관의 종류에 따라 보관할 수 있는 유효기간이 있습니다.

오늘 날짜를 기준으로 유효기간이 지났음에도 파기되지 않은 개인정보의 번호를 반환하는 문제입니다.

변수는 다음과 같습니다.

- today : 오늘 날짜 "2022.05.19"

- terms : 약관과 약관의 유효기간 ["A 6", "B 12", "C 3"]

- privacies : 개인정보의 수집 일자와 약관 종류 ["2021.05.02 A", "2021.07.01 B", "2022.02.19", "2022.02.28 C"]

따라서 위 예시의 경우, 유효기간이 지나서 파기해야 할 개인정보 번호는 [1,3] 입니다.

 

2. 접근 방법

다음과 같이 접근하였습니다.

먼저 입력으로 주어지는 데이터들을 간단하게 전처리해줘야 합니다.

공백으로 구분됐는지, "."(온점)으로 구분됐는지 등을 보면서 적절하게 split과 replace 함수를 써주시면 좀 더 낫습니다.

 

우선 첫 번째 today(날짜)를 연, 월, 일로 나누었습니다.

취향에 따라 다를 것 같은데, 저는 좀 더 직관적으로 이해하려고 "."을 제외하고 슬라이싱하여 year, month, day로 구분하였습니다.

 

두 번째 terms 변수를 이용해 약관별 유효기간 dictionary를 정의했습니다.

Key를 약관 종류(A, B, C ...), 그리고 Value를 유효기간(duration)으로 정의하여 값을 저장했습니다.

변수명은 그냥 귀찮아서 duration으로 했습니다... 어차피 저만 알아보면 되니까 ...

 

728x90

 

 

세 번째privacies 변수를 이용해 각 개인정보별 유효기간을 판단해주면 됩니다.

크게 3번의 과정으로 나뉠 수 있는데요.

우선 privacies의 원소의 개수에 따라 n번 loop를 해줘야겠죠.

 

(1) i번째 case인 privacy : "2021.05.02 A"를 두 변수(a_date, a_term)으로 정의함.

공백으로 구분돼있으므로 앞은 개인정보 수집 일자, 뒤는 해당 약관이 되겠죠.

a_date 변수는 위 1번 today 변수처럼 연, 월, 일로 나눠줍니다.

a_term은 두 번째 과정에서 정의한 약관별 유효기간 dictionary를 활용해 약관 종류에 따른 유효기간을 가져오는 데 활용합니다.

 

(2) 약관별 유효기간에 따른 개인정보 수집 일자에서 유효기간이 지났을 때의 날짜 구해줌.

이 프로그램의 궁극적인 목적은 개인정보 수집 일자에서 유효기간이 지난 날짜가 오늘 날짜(today)보다 지났는지 안 지났는지를 판단해주는 것입니다.

그러므로 개인정보 수집 일자에서 유효기간이 지날 때의 시점을 구해줘야겠죠.

쉽게 말하면 유통기한을 구해주면 됩니다.

새로운 개월수(유통기한)을 구하기 위해 유효기간을 a_date에서 쪼갠 월(a_date_month) 변수에 더해줍니다.

만약 a_date가 10월이고, a_term에 따른 유효기간이 5개월이라면 새로운 개월수는 15개월이 됩니다.

이렇게 기존 일자에 유효기간을 더해준 변수를 사용한다면 장점이 있습니다.

예를 들어 a_date가 10월이고 2개월 뒤가 유효기간 만료라면 12월이 유통기한임을 알 수 있습니다.

하지만 3개월 뒤라면 내년 1월이 되겠네요. "내년 1월"을 다시 정의하면 "1년(12개월) + 1개월"으로 구분할 수 있습니다.

새로운 개월수(유통기한)을 12로 나눴을 때 몫을 q, 나머지를 r 이라고 하면

유통기한은 현 시점으로부터 q년 뒤 r월이 됩니다.

(현 시점: 2021년 10월 -> 3개월 뒤 -> 13개월(10월 + 3개월 = 12개월 + 1개월) -> 유통기한 : 1년 뒤 1월 )

 

그리고 이를 조건에 따라 적절히 변환해줘야 합니다.

우리가 고려해야 할 조건은 다음과 같습니다.

 

(a) 만약 개인정보 수집 일자(a_date)의 일자가 1일이라면?

- 예를 들어 1월 1일에서 2개월 후 날짜는 언제가 될까요? 바로 3월 1일이 아니라 2월의 마지막 날이 됩니다.

- 문제에서 매달 마지막 날은 28일이라고 정의했으므로, 위 예시에선 2월 28일이 되겠네요.

- 즉 일자가 1일일 때 k개월 후 날짜는 k-1개월 후의 28일이 됨을 알 수 있습니다.

- 1일이 아니라면 그냥 수집 일자에서 1일을 빼주면 됩니다. (ex. 2월 23일 -> 2개월 후 -> 4월 22일)

 

(b) 만약 새로운 개월수(유통기한)이 12개월을 넘는다면?

- 개인정보 수집 일자에서의 월에 해당하는 a_date_month 변수에 유효기간을 더해서 new_month를 정의했습니다.

- 이때 new_month가 12개월 이상이라면 해가 바뀌게 되므로 새롭게 고려해줘야 합니다.

- 크게 new_month가 12의 배수인지(즉 나머지가 0인지), 12의 배수가 아닌지 2가지 경우로 구분할 수 있습니다.

- 만약 12의 배수라면(나머지가 0이라면), 몫을 q라고 했을 때 "q-1년 뒤" 12월이 됩니다.

- 다음 예시를 봅시다.

(현 시점: 2021년 10월 -> 2개월 뒤 -> 12개월(10월 + 2개월 = 12개월 + 0개월) -> 유통기한 : 0(1-1)년 뒤 12월 )

- 이해가 되시죠? 저는 개인적으로 이 부분이 좀 헷갈리는 부분이었습니다.

- 그러므로 현 시점의 연도로부터 q-1년을 더해주고, 새로운 월은 12월이 됩니다.

 

예를 들어 terms = ["A 12"], privacies = ["2010.01.01 A"] 라고 해볼까요.

2010년 1월 1일을 기준으로 유효기간이 12개월이니 12개월 뒤 날짜인 유통기한은 "2010.12.28"이 된다는 겁니다.

먼저 현시점 1월에 유효기간 12월을 더해주면 새로운 개월수는 13개월이 됩니다.

이때 (a) 조건에 따라 일자가 1일이므로, 일자는 28일로 바꿔주고 1개월 빼줘야 하므로 13개월이 아닌 12개월이 됩니다.

그리고 (b) 조건에 따라 12의 배수이므로 몫인 q에서 1을 빼준 값을 a_date의 연도에 더해줘야겠죠?

근데 새로운 개월수가 12개월이므로, 12로 나눠주면 몫은 q=1입니다. 그러면 1 빼줘봐야 0이 되네요. 연도는 바뀌지 않습니다.

대신 월은 12월이 되고, 일은 (a)조건에 따라 28일이 되니, 유통기한은 2010.12.28이 됩니다.

즉 2010.01.01을 기준으로 12개월 후의 날짜는 2010.12.28이 된다는 겁니다. 이해되시죠?

 

만약 새로운 개월수가 12의 배수가 아니라면 12로 나눠준 몫 q를 연도에 더해주고, 나머지 r을 새로운 월로 정의해주시면 됩니다.

 

(c) 만약 새로운 개월수(유통기한)이 12개월을 넘지 않는다면?

쉽게 말하면 현 시점이 3월이고, 유효기간이 2개월이어서 3+2 = 5가 된 케이스죠.

그러면 그냥 연도는 바뀌지 않으므로 월만 바꿔서 3+2 = 5월로 정의해주시면 됩니다.

 

(3) 새롭게 정의한 유통기한과 오늘 날짜(today)를 비교해주면 됨.

비교하는 코드는 어렵지 않아서 읽어보시기만 해도 이해되실 거라 생각합니다.

 

3. 코드

# 프로그래머스 lv.1
# 개인정보 수집 유효기간 (카카오 2023 채용)
# today : 오늘 날짜 "2022.05.19"
# terms : 약관종류 및 유효기간 "A3 : A약관 3개월" / 유효기간은 1 ~ 100 사이 정수
# privacies : 개인정보수집일자 및 약관 종류 "2019.05.02 A : A약관이 수집된 일자가 2019.05.02"
# 입력된 데이터를 보고 파기해야할 개인정보의 번호(Privacies의 해당 인덱스+1)를 답함

def solution(today, terms, privacies):
    # 1. 날짜 연,월,일별로 구분하기 ex. 2022.05.19
    today = today.replace(".", "") # 20220519
    year = today[:3+1] ; year = int(year) #2022
    month = today[4:5+1] ; month = int(month) #05
    day = today[6:] ; day = int(day)#19
    
    # 2. terms -> 약관별 유효기간 사전 만들기
    terms_dict = dict()
    len_terms = len(terms)
    for i in range(len_terms):
        a = terms[i].replace(" ", "")
        term = a[0] # 약관 종류
        duration = int(a[1:]) # 유효기간
        terms_dict[term] = duration # A6 -> terms_dict['A'] = 6
    
    # 3. privacies -> 각 개인정보별 유효기간 판단하기
    n = len(privacies)
    answer = []
    for j in range(n):
        privacy = privacies[j] # "2021.05.02 A"
        a_date, a_term = privacy.split(" ")
        
        # a_term에 대한 유효기간 가져오기
        duration = terms_dict[a_term] # if A 6 -> duration = 6
        
        # a_date -> 날짜 쪼개기
        a_date = a_date.replace(".", "") #20190101
        a_date_year = int(a_date[:3+1])#2019
        a_date_month = int(a_date[4:5+1]) #01
        a_date_day = int(a_date[6:]) #01
        
        # a_date에 유효개월 더해서 유효기간 구함
        new_month = a_date_month + duration
        
        # a_date_day도 최신화
        if a_date_day == 1:
            a_date_day = 28
            new_month = new_month - 1
        else:
            a_date_day = a_date_day - 1
        
        if new_month >= 12:
            # (1) new_month % 12 == 0
            if new_month % 12 == 0 :
                # 나머지가 0이면 12월로 해야함.
                a_date_month = 12
                plus_year = (new_month // 12)-1
                a_date_year += plus_year
            else: # (2) new_month % 12 != 0인 경우
                a_date_year += (new_month // 12)
                a_date_month = (new_month % 12)
                
        else:
            a_date_month = new_month
                
        
        # 날짜 판단하기
        if a_date_year > year:
            # 유효기간이 더 길음 : 패스
            continue
        elif a_date_year < year:
            # 유효기간이 지남!! : 인덱스 추가
            answer.append(j+1)
            continue
        elif a_date_year == year:
            # 연도 같음 : 월 비교
            if a_date_month > month:
                # 유효 기간이 더 길음 : 패스
                continue
            elif a_date_month < month:
                # 유효기간이 지남!! : 인덱스 추가
                answer.append(j+1)
                continue
            elif a_date_month == month:
            # 월 같음 : 일 비교
                if a_date_day >= day:
                    # 유효 기간이 더 길음 : 패스
                    continue
                elif a_date_day < day:
                    # 유효 기간 지남
                    answer.append(j+1)
    return answer

 

감사합니다.

잘 읽으셨다면 게시글 하단에 ♡(좋아요) 눌러주시면 감사하겠습니다 :)

(구독이면 더욱 좋습니다 ^_^)

* 본 블로그는 학부생이 운영하는 블로그입니다.

따라서 포스팅에 학문적 오류가 있을 수 있으며, 이를 감안해서 봐주시면 감사하겠습니다.

 


- 간토끼(DataLabbit)

- B.A. in Economics, Data Science at University of Seoul

728x90