본문 바로가기
코딩테스트 준비/프로그래머스

[프로그래머스][C++] 개인정보 수집 유효기간

by 스테디코디스트 2023. 10. 25.
반응형

<문제 소개>


<소스 코드>

#include <string>
#include <vector>
#include <map>

using namespace std;

vector<int> solution(string today, vector<string> terms, vector<string> privacies) 
{
    vector<int> answer;
    
    // 현재 날짜
    int curYear = (today[2] - '0') * 10 + (today[3]- '0');
    int curMonth = (today[5]- '0') * 10 + (today[6]- '0');
    int curDay = (today[8]- '0') * 10 + (today[9]- '0');    
    
    // 약관 종류별 보관 달 수
    map<char, int> storage; 
    
    for(int i = 0; i < terms.size(); i++)
    {
        if(terms[i].size() == 3)
        {
            // 9개월 이하
            storage[terms[i][0]] = terms[i][2] - '0';    
        }
        else if(terms[i].size() == 4)
        {
            // 10개월 이상 100개월 미만
            storage[terms[i][0]] = (terms[i][2] - '0') * 10 + (terms[i][3] - '0'); 
        }
        else
        {
             // 100개월
            storage[terms[i][0]] = 100;
        }        
    }
    
    for(int i = 0; i < privacies.size(); i++)
    {
        string curPrivacy = privacies[i];
        
        // 개인정보 수집 일자
        int year = (curPrivacy[2] - '0') * 10 + (curPrivacy[3]- '0');
        int month = (curPrivacy[5]- '0') * 10 + (curPrivacy[6]- '0');
        int day = (curPrivacy[8]- '0') * 10 + (curPrivacy[9]- '0');  
        
        // 약관 종류
        char curTerm = curPrivacy[11];
        
        // 보관 달 수 만큼 더해줌
        month += storage[curTerm];
        
        // 일 수를 하루 빼줌
        day -= 1;
        
        if(day == 0)
        {
            // 원래 1일이었던 경우
            day = 28;
            month -= 1; // 한 달을 빼줌(전달 말일이 됨)
        }
        
        if(month > 12)
        {
            // 12월이 넘어간 경우
            int res = month / 12;
            
            month %= 12;
            year += res;
            
            if(month % 12 == 0)
            {
                month += 12;
                year -= 1;
            }
        }
        
        // 개인정보 수집일자 -> 약관일자를 더해 개인정보 파기 일자가 됨
        
        if(curYear < year)
        {
            // 현재 년도 < 개인정보 파기 년도 -> 파기x
            continue;
        }
        else if(curYear == year)
        {
            // 현재 년도 = 개인정보 파기 년도
            if(curMonth < month)
            {
                // 현재 달 < 개인정보 파기 달 -> 파기x
                continue;
            }
            else if(curMonth == month)
            {
                // 현재 달 = 개인정보 파기 달
                if(curDay <= day)
                {
                    // 현재 일 <= 개인정보 파기 일 -> 파기x
                    continue;
                }
                else
                {
                    // 현재 일 > 개인정보 파기 일 -> 파기
                    answer.push_back(i+1);
                    continue;
                }
            }
            else
            {
                // 현재 달 > 개인정보 파기 달 -> 파기
                answer.push_back(i+1);
                continue;
            }
        }
        else
        {
            // 현재 년도 > 개인정보 파기 년도 -> 파기
            answer.push_back(i+1);
            continue;
        }
    }    
    
    return answer;
}

<소스코드 2> - 다른 분의 풀이

#include <algorithm>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

using namespace std;
vector<int> solution(string today, vector<string> terms, vector<string> privacies) 
{
    vector<int> answer;
    
    // 년월일을 추출
    int year = stoi(today.substr(0, 4));
    int month = stoi(today.substr(5, 2));
    int days = stoi(today.substr(8));
    
    // 년월을 모두 일로 환산한 값
    int todayD = (year)*12 * 28 + (month - 1) * 28 + days;

    vector<int> ar(privacies.size());
    map<char, int> mp;
    
    for (int i = 0; i < terms.size(); i++) 
    {
        stringstream ss(terms[i]);
        
        char c;
        int month;
        
        ss >> c >> month;
        
        mp[c] = month; // 약관 종류별 개월 수 매핑
    }
    
    for (int i = 0; i < privacies.size(); i++) 
    {
    	// 년월일을 추출
        int y = stoi(privacies[i].substr(0, 4));
        int m = stoi(privacies[i].substr(5, 2));
        int d = stoi(privacies[i].substr(8, 2));
        char c = privacies[i].back();
        
        // 년월일을 환산한 값 + 약관 종류별 보관 개월 수를 환산한 값 - 1일
        ar[i] = (y)*12 * 28 + (m - 1) * 28 + d + mp[c] * 28 - 1;
    }
    
    for (int i = 0; i < ar.size(); i++) 
    {
    	// 환산한 현재일자와 파기일자를 비교
        // 파기일자가 현재일자보다 이른 경우 파기 -> answer에 추가
        if (ar[i] < todayD) 
        {
            answer.push_back(i + 1);
        }
    }
    
    return answer;
}

<풀이과정>

1. 아스키코드와 문자열 내의 고정된 년,월,일의 자리를 이용하여 현재 today의 년,월,일을 구한다.

2. 약관 종류별 보관 개월 수를 쉽게 찾기 위해 map 컨테이너를 이용해 하나씩 매핑해주었다.

3. 이때도 마찬가지로 고정된 문자열의 자리수와 아스키코드를 이용해 구한 개월 수를 넣어주었는데 개월 수는 100개월까지 가능하기 때문에, 1자리수 개월 수인 경우와, 10자리수 개월 수인 경우, 100자리수 개월 수인 경우에 따라 문자열의 길이가 달라지는 것을 이용해 구분하여 값을 넣어주었다.

4. 다음으로는 개인정보 수집 일자들의 목록 privacies를 반복하여 각각의 개인정보 일자들에 접근했고, 해당 접근 일자를 분석해 앞서 today의 년월일을 구한 것과 마찬가지 방법으로 년월일을 구해준다.

5. 또한 개인정보 수집 일자와 같이 기록된 약관 종류를 파악하고, 앞서 매핑했던 내용을 바탕으로 약관 종류별 해당 개월 수를 찾을 수 있다.

6. 이제 개인정보 파기 일자를 구해 현재 일자와 비교하여 파기해야하는지 판단해야 하므로 개인정보 파기 일자에 대한 정보를 구해야한다.

7. 개인정보 파기 일자는 앞서 구한 개인정보 수집 일자에서 보관 개월 수를 더해주고, 하루를 뺀 날까지만 보관할 수 있다는 점을 이용하여 구할 수 있다.

8. 따라서 앞서 구한 현재 개인정보 수집 년월일 정보에서의 월의 정보인 month에 약관 개월 수를 더해주고, 일의 정보인 day는 하루를 빼준다.

9. 위와 같이 개인정보 파기 일자를 구할 수 있는데 몇가지 예외사항이 있어 해당 경우를 확인하고 넘어가야 한다.

9-1. 하루를 뺀 day가 0일인 경우

- 원래 날짜가 1일이어서 하루를 뺀 날짜가 0일이 되는 경우, 해당 날짜는 매 달의 마지막 날짜인 28일로 바꿔주고, 기존 month에서 한 달을 빼준다. 

- 즉, 전달 말일로 변경해준다.

9-2. 개월 수를 더한 month가 12월을 넘어가는 경우

- 개월 수는 최대 100까지 가능하기 때문에 month에 개월 수를 더한 값이 마지막 달인 12월을 넘어가게 될 수 있다.

- 따라서 이때는 month를 12로 나눈 몫과 나머지의 값을 이용해 넘어가는 월은 12로 나눈 나머지의 값을 취하고, 월이 넘어가서 증가한 year의 값은 기존 year의 값에 넘어간 년도의 값인 12로 나눈 몫의 값을 더해준다.

- 하지만 이때 month가 12의 배수가 되어 month를 12로 나눈 나머지가 0이되어 0월이 되는 경우에는 12월에 해당하는 경우이므로, month에는 12를 더해주고, 0월이 될때 넘어간 1년도 다시 돌려줘야 하기에 year의 값도 1을 빼준다.

10. 위의 과정으로 개인정보 수집일자에 약관일자를 더해 개인정보 파기일자를 구할 수 있었다. 이제 이 개인정보 파기일자를 현재일자와 비교하여 실제 파기여부를 파악 해야한다.

11. 제일 처음에 구한 today의 년월일과 방금 구한 개인정보 파기일자의 년월일을 비교한다.

12. 년도부터 차례대로 비교를 진행하는데, 현재 년도가 아직 파기일자 년도를 지나지 않았다면 넘어가고, 파기일자 년도를 지났다면 해당 정보는 파기해야하므로 asnwer에 해당 정보의 번호를 넣어준다.(번호는 1부터 시작이므로 반복자 i에 1을 더한 값으로 구할 수 있다.)

13. 만약 년도가 같은 경우에는 월을 비교하고 위와 같은 과정을 반복한다.

14. 월도 같다면 일을 비교하여 현재 일이 파기 일을 지나지 않은 경우에는 넘어가고, 파기 일을 넘었다면 파기해준다.

15. 위의 반복이 모두 끝난 후 answer을 리턴해준다.


<코멘트>

개인적으로 조금 어려웠던 문제였다.

테스트 17번의 반례를 못 찾아서 한참 걸렸다ㅠㅠ

다른분들이 질문한 내용들 중에 반례를 하나하나 다 대입해보고서야 겨우 찾을 수 있었다.ㅋㅋㅋ

 

 

 

좀 더 나은 풀이를 공부하고자 다른 사람들의 풀이를 보고 좋은 풀이가 있어 해당 소스코드도 같이 첨부한다.


<제출결과>