문제 본문 (Problem Presentation)
2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각 SUN,MON,TUE,WED,THU,FRI,SAT
입니다. 예를 들어 a=5, b=24라면 5월 24일은 화요일이므로 문자열 "TUE"를 반환하세요.
제한 조건
2016년은 윤년입니다.2016년 a월 b일은 실제로 있는 날입니다. (13월 26일이나 2월 45일같은 날짜는 주어지지 않습니다)
나의 풀이 (My Solution)
3줄 접근 (3-sentence approach)
핵심 접근
"1월 1일을 기준점(0일 경과)"으로 삼아, 목표 날짜까지의 총 경과 일수를 구한 뒤, (경과일 + 기준 요일 인덱스) % 7로 요일을 계산하는 방식입니다. standardDate = 5는 금요일(FRI)이 dayEnums 배열에서 인덱스 5에 해당하기 때문이고, 경과일에 더해 7로 나눈 나머지가 그대로 요일 인덱스가 됩니다.
코드 (Code)
class Solution {
public String solution(int month, int day) {
String answer;
int standardDate = 5; // 조건: 1월 1일은 금요일이므로
int[] days = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
String[] dayEnums = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
int elapsedDays = 0;
for(int i = 0; i < month - 1; i++) {
elapsedDays += days[i];
}
elapsedDays += day - 1; // 1월 1일은 0일 경과이므로
answer = dayEnums[(elapsedDays + standardDate) % 7];
return answer;
}
}
분석 (Analysis)
- 시간 복잡도 (Time Complexity) : O(1)
- 공간 복잡도 (Space Complexity) : O(1)
- 사용하는 자료구조 (Data Structure) : 배열(int[])
장점
- 직관적인 수학적 모델링을 사용하고 있습니다. 날짜 계산을 "며칠이 지났는가"라는 단순한 누적 합산으로 환원한 덕분에 코드 흐름이 명확합니다.
- 각 월의 일수 배열(days)과 요일 문자열 배열(dayEnums)을 분리해 데이터와 로직을 구분한 점도 가독성에 좋습니다.
- 주석으로 standardDate와 elapsedDays 초기값의 의도를 설명한 점도 유지보수에 도움이 됩니다.
- 연도가 바뀌어도 standardDate와 days[1](2월 일수) 딱 두 곳만 수정하면 된다. 수정 지점이 명확하게 고립되어 있다는 점이 설계의 장점.
한계
- 첫째, 2016년에 하드코딩된 풀이입니다. days 배열의 2월이 29일(윤년 기준)로 고정되어 있고, standardDate = 5도 2016년 1월 1일이 금요일이라는 조건에 종속됩니다. 다른 연도로 일반화하려면 윤년 판별 로직과 기준 요일 계산 로직이 추가로 필요합니다.
- 둘째, Java 표준 라이브러리를 활용하지 않았습니다. java.time.LocalDate나 java.util.Calendar를 쓰면 날짜 배열 없이 훨씬 짧고 안전하게 구현할 수 있습니다. 실무에서는 직접 날짜 계산보다 검증된 라이브러리 활용이 권장됩니다.
- 셋째, answer 변수가 선언 직후 바로 대입되므로 초기값 없이 선언한 것이 사소하게 불필요합니다. 선언과 동시에 대입하는 것이 더 깔끔합니다.
- 완벽한 일반화로 가기 위해선 윤년 판별 로직과 1월 1일 요일 계산까지 추가해야 하므로, 현재 풀이는 "라이브러리 없는 풀이 중 가장 확장이 쉬운 구조"다.
다른 답안 # 1
import java.util.*;
class TryHelloWorld
{
public String getDayName(int month, int day)
{
Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
.setDate(2016, month - 1, day).build();
return cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, new Locale("ko-KR")).toUpperCase();
}
public static void main(String[] args)
{
TryHelloWorld test = new TryHelloWorld();
int a=5, b=24;
System.out.println(test.getDayName(a,b));
}
}
핵심 접근
Calendar.Builder로 2016년 특정 날짜를 설정하고 getDisplayName()으로 요일 이름을 직접 꺼냅니다. 날짜 계산 로직을 자바 표준 라이브러리에 전부 위임합니다.
분석
- 시간 복잡도: O(1)
- 공간 복잡도: O(1)
- 사용하는 자료구조: Calendar 클래스 (필드 배열, Locale 정보, TimeZone 등을 포함한 내부적으로 꽤 무거운 자료구조)
장점
- 월별 일수 배열이나 기준 요일 상수가 전혀 필요 없습니다. 라이브러리가 윤년과 날짜 계산을 알아서 처리하므로 버그가 생길 여지가 없고, 연도를 바꿔도 즉시 동작합니다.
한계
- Calendar는 Java 8 이후로 java.time에 밀려 레거시 API로 취급됩니다.
- getDisplayName()의 반환값이 Locale 설정에 따라 달라질 수 있어, 한국어 Locale로 설정하면 "화", "수" 같은 한글이 나올 수도 있어 toUpperCase()만으로는 부족할 수 있습니다.
다른 답안 # 2
import java.time.*;
class Solution {
public String solution(int a, int b) {
return LocalDate.of(2016, a, b).getDayOfWeek().toString().substring(0,3);
}
}
핵심 접근
LocalDate.of(2016, a, b).getDayOfWeek().toString().substring(0, 3)로 날짜 생성, 요일 추출, 문자열 자르기를 체이닝 한 줄로 해결합니다.
분석
- 시간 복잡도: O(1)
- 공간 복잡도: O(1)
- 사용하는 자료구조: LocalDate (연, 월, 일 int 3개로 구성된 경량 객체)
장점
- 코드가 가장 짧고 현대적인 Java 스타일입니다. LocalDate는 불변 객체라 스레드 안전하고, 윤년·월말 처리를 모두 내부에서 처리합니다.
한계
- getDayOfWeek().toString()은 "TUESDAY" 형태의 전체 이름을 반환하므로, 앞 3글자를 자르는 substring(0, 3) 트릭에 의존합니다. 만약 요일 형식이 바뀌는 상황이라면 취약하고, 문제 조건("1월 1일은 금요일")이 실제 달력과 다른 가상의 상황이었다면 이 풀이는 아예 사용할 수 없습니다.
인사이트
- 내 풀이가 라이브러리 사용이 제한된 환경에서는 가장 이상적인 접근이라는 점이 감동이다.
Github
https://github.com/ginsengcandy/Coding-Test-Practice/commit/511d62ea58cc9558e4889112acf4357cf5df3e7b
[level 1] Title: 2016년, Time: 0.03 ms, Memory: 85.5 MB -BaekjoonHub · ginsengcandy/Coding-Test-Practice@511d62e
+ int[] days = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
github.com
문제 및 학습 자료 출처
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr