Home [프로그래머스] 2023 KAKAO BLIND RECRUITMENT - 개인정보 수집 유효기간
Post
Cancel

[프로그래머스] 2023 KAKAO BLIND RECRUITMENT - 개인정보 수집 유효기간

0️⃣ 문제 링크

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

1️⃣ 문제 설명

오늘 날짜(today), 약관별 유효기간(terms) 그리고 개인정보 수집일(privacies)이 주어진다.
각 개인정보가 오늘 날짜 기준으로 유효기간이 만료되었는지 판별하여 파기해야 할 개인정보 번호를 오름차순으로 반환하는 문제이다.

  • 날짜 : “YYYY.MM.DD” 형식의 문자열
  • 파기 기준 : 수집일자 + 약관기간 ≤ 오늘 날짜

2️⃣ 문제 접근 방식

  • 날짜 문자열을 정수 배열로 변환
    • “YYYY.MM.DD” → [YYYY, MM, DD]
    • 별도 함수 changeFormat()으로 분리
  • 약관 정보를 HashMap으로 저장
    • 각 약관의 종류에 따라 유효 개월 수를 바로 조회할 수 있도록 Map<String, Integer> 사용
  • 각 개인정보에 대해 만료 여부 판단
    • 수집일자에 약관 개월 수를 더해 만료일 계산
    • 달 수가 12를 넘을 경우 → 연도 계산 처리
    • 오늘 날짜(tDate)와 비교하여 파기 대상이면 결과 리스트(ans)에 추가

시간 복잡도 : O(N) → (N = privacies 길이) 각 개인정보를 한 번씩만 검사
공간 복잡도 : O(T + N) → 약관 저장용 Map + 개인정보 검사 리스트

3️⃣ 전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.util.*;

class Solution {
    public int[] solution(String today, String[] terms, String[] privacies) {
        // 오늘 날짜를 [YYYY, MM, DD] 형태로 변환
        int[] tDate = changeFormat(today);
        
        // 약관 종류별 유효기간(개월) 저장
        Map<String, Integer> term = new HashMap<>();
        for (String str : terms) {
            String[] s = str.split(" ");
            term.put(s[0], Integer.parseInt(s[1]));
        }
        
        ArrayList<Integer> ans = new ArrayList<>();
        
        // 각 개인정보의 만료 여부 검사
        for (int i = 0; i < privacies.length; i++) {
            String[] s = privacies[i].split(" ");
            int[] pDate = changeFormat(s[0]);
            
            // 약관 기간(개월) 더하기
            int mon = pDate[1] + term.get(s[1]);
            
            // 달이 12를 초과할 경우 연도 보정
            if (mon > 12) {
                if (mon % 12 == 0) {
                    pDate[0] += mon / 12 - 1;
                    mon = 12;
                } else {
                    pDate[0] += mon / 12;
                    mon %= 12;
                }
            }
            pDate[1] = mon;
            
            // 오늘 날짜와 만료일 비교
            if (tDate[0] > pDate[0]) {
                ans.add(i+1);
                continue;
            } else if (tDate[0] == pDate[0]) {
                if (tDate[1] > pDate[1]) {
                    ans.add(i+1);
                    continue;
                } else if (tDate[1] == pDate[1]) {
                    if (tDate[2] >= pDate[2]) {
                        ans.add(i+1);
                        continue;
                    }
                }
            }
        }
        
        // ArrayList -> int[] 변환
        int[] answer = new int[ans.size()];
        for (int i = 0; i < ans.size(); i++) {
            answer[i] = ans.get(i);
        }
        return answer;
    }
    
    // 날짜 포맷 변환 함수
    static int[] changeFormat(String date) {
        String[] str = date.split("\\."); // 정규식: '.'은 메타문자이므로 '\\.'로 이스케이프 필요
        int[] res = new int[3];
        for (int i = 0; i < 3 ; i++) {
            res[i] = Integer.parseInt(str[i]);
        }
        return res;
    }
}

4️⃣ 다른 풀이

  • 날짜를 총 일수로 환산해서 비교하면 간단
  • 예를 들어 “2022.05.19” → 20221228 + 5*28 + 19 이런 식으로 변환하면, 같은 기준에서 그냥 단순 비교 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.*;

class Solution {
    public int[] solution(String today, String[] terms, String[] privacies) {
        int tDate = toDays(today);

        // 약관 기간 저장
        Map<String, Integer> term = new HashMap<>();
        for (String str : terms) {
            String[] s = str.split(" ");
            term.put(s[0], Integer.parseInt(s[1]));
        }

        ArrayList<Integer> ans = new ArrayList<>();
        for (int i = 0; i < privacies.length; i++) {
            String[] s = privacies[i].split(" ");
            int start = toDays(s[0]);
            int expire = start + term.get(s[1]) * 28; // 한 달 = 28일 기준

            if (expire <= tDate) ans.add(i + 1);
        }

        return ans.stream().mapToInt(Integer::intValue).toArray();
    }

    // 날짜를 "YYYY.MM.DD" → 총 일수로 변환
    static int toDays(String date) {
        String[] str = date.split("\\.");
        int y = Integer.parseInt(str[0]);
        int m = Integer.parseInt(str[1]);
        int d = Integer.parseInt(str[2]);
        return (y * 12 * 28) + (m * 28) + d;
    }
}

5️⃣ 회고 및 배운점

💡 오답 원인

  • 날짜 split 시 date.split(".") 로 작성하여 정규식 오류 발생 ("."은 모든 문자를 의미함 → "\\."로 수정)
  • 달 계산 시 mon % 12 == 0 인 경우를 고려하지 않아 연도 계산 틀림
    • 예: 2021.12 + 12개월 = 2022.12가 아닌 2023.00으로 처리되는 문제

💡 배운 점

날짜 계산 문제는 단위 변환으로 단순화하는 게 가독성과 안정성 등 모든 면에서 편리하다는 것을 깨닫게 되었다.
자바 문자열 안에서의 정규식을 표현하는 방식에 대해 알 수 있었던 기회였다.
항상 ArrayList<Integer> → int[] 변환에 대해 고민을 하는데, 가장 간단한 방법(반복문 이용)이 있다는 것을 잊지 말아야겠다.

This post is licensed under CC BY 4.0 by the author.

[코딩테스트] Java 정리 - 3

-