▼ Why ? What ?
1일 1알고리즘 스터디에서 "개인정보 수집 기간"이라는 문제를 풀었는데, 문제를 해결하기 위한 키포인트를 찾는 것은 어렵지 않았지만, 반례를 찾기가 까다로웠고 `.`을 기준으로 문자열을 자를 때 주의할 점도 알아둬야 할 것 같아서 정리해봤다.
▼ 알고리즘 문제 : "개인정보 수집 기간"
개인정보보 수집 기간
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
" . "을 구분자로 문자열을 자를 때 주의할 점
- 정규 표현식에서 "."은 모든 문자를 의미하기 때문에, `String.spllit(".")`은 올바르지 않다 !
➙ `String.split("\\.")`처럼 사용해야 한다 !
[ 나의 해결 코드 1 ]
- 날짜 형식 그대로 현재 날짜와 비교하여 유효 날짜인지 검증하는 방식으로 해결하였다.
( 모든 달이 28일이라는 점을 깜빡했다.. )
➙ 일수로 변환하여 비교하는 로직이었다면, `month + term`이 12의 배수가 되는 경우에 발생하는 반례를 고려해줄 필요가 없어 더 좋았을 것 같다 !
import java.util.*;
class Solution {
public int[] solution(String today, String[] terms, String[] privacies) {
HashMap<String, Integer> hsmp = new HashMap<>();
for (String t : terms) {
String[] term = t.split(" ");
hsmp.put(term[0], Integer.valueOf(term[1]));
}
String[] td = today.split("\\.");
int[] tdInt = new int[3];
for (int i = 0; i < 3; ++i) {
tdInt[i] = Integer.valueOf(td[i]);
}
// 파기해야 할 개인정보 리스트
List<Integer> list = new ArrayList<>();
for (int i = 0; i < privacies.length; ++i) {
boolean isValid = false;
// privacy[0] : 유효기간, privacy[1] : 약관 종류
String[] privacy = privacies[i].split(" ");
// date[0] : 연도, date[1] : 월, date[2] : 일
String[] date = privacy[0].split("\\.");
int[] dateInt = new int[3];
for (int j = 0; j < 3; ++j) {
dateInt[j] = Integer.valueOf(date[j]);
}
int month = dateInt[1];
int term = hsmp.get(privacy[1]);
if ((month + term) > 12) {
if ((month + term) % 12 == 0) {
dateInt[0] += (month + term) / 12 - 1;
dateInt[1] = 12;
} else {
dateInt[0] += (month + term) / 12;
dateInt[1] = (month + term) % 12;
}
} else {
dateInt[1] = month + term;
}
for (int j = 0; j < 3; ++j) {
if (dateInt[j] < tdInt[j]) { // 유효 기간이 끝난 경우
break;
} else if (dateInt[j] > tdInt[j]) { // 유효 기간이 남아있는 경우
isValid = true;
break;
}
}
if (!isValid) {
list.add(i+1);
}
}
Collections.sort(list);
// 정수형 배열 생성
int[] answer = new int[list.size()];
// 리스트의 요소를 배열에 복사
for (int i = 0; i < list.size(); i++) {
answer[i] = list.get(i);
}
return answer;
}
}
[ 나의 해결 코드 2 ]
- 일수로 변환하여 계산하니 코드도 간결해지고, 로직의 복잡도도 감소했다.
➙ 구현 문제이더라도 어떻게 하면 더 간단한 로직으로 해결할 수 있을지 고민하는 연습이 필요하다고 느꼈다 ! - List를 int형 배열로 변환하는 과정을 `stream()`을 이용해서 간단하게 바꿔봤는데, 이 방법은 가독성은 올라가지만 for문으로 일일히 배열에 값을 넣는 것(`for-loop`)보다 성능이 떨어진다.
import java.util.*;
class Solution {
public int[] solution(String today, String[] terms, String[] privacies) {
HashMap<String, Integer> hsmp = new HashMap<>();
for (String t : terms) {
String[] term = t.split(" ");
hsmp.put(term[0], Integer.valueOf(term[1]));
}
int tdDate = getDate(today);
// 파기해야 할 개인정보 리스트
List<Integer> list = new ArrayList<>();
for (int i = 0; i < privacies.length; ++i) {
// privacy[0] : 유효기간, privacy[1] : 약관 종류
String[] privacy = privacies[i].split(" ");
// 일수로 변환하고 약관에 해당하는 기간을 더한다.
int tmpDate = getDate(privacy[0]) + hsmp.get(privacy[1]) * 28;
if (tdDate >= tmpDate) {
list.add(i+1);
}
}
// int형 배열로 변환하고 결과값으로 반환
return list.stream().mapToInt(i -> i).toArray();
}
// 일수로 변환하는 메서드 - 중복 코드 줄이기
private int getDate(String today) {
String[] date = today.split("\\.");
int year = Integer.parseInt(date[0]);
int month = Integer.parseInt(date[1]);
int day = Integer.parseInt(date[2]);
return (year * 12 * 28) + (month * 28) + day;
}
}