0️⃣ 문제 링크
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[]
변환에 대해 고민을 하는데, 가장 간단한 방법(반복문 이용)이 있다는 것을 잊지 말아야겠다.