ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [프로그래머스 2단계] 알고리즘 26. 2016년
    레거시/레거시-알고리즘(3) 2018. 4. 12. 12:33
    반응형

    문제 출처는 프로그래머스 알고리즘 연습 에서 볼 수 있습니다!(https://programmers.co.kr/learn/challenges)


    알고리즘 26. 2016년


    2016년 1월 1일은 금요일입니다. 2016년 A월 B일은 무슨 요일일까요? 두 수 A,B를 입력받아 A월 B일이 무슨 요일인지 출력하는 getDayName 함수를 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각

    SUN,MON,TUE,WED,THU,FRI,SAT

    를 출력해주면 됩니다. 예를 들어 A=5, B=24가 입력된다면 5월 24일은 화요일이므로 TUE를 반환하면 됩니다.

    #include<iostream>
    #include<string>
    using namespace std;

    string getDayName(int a,int b)
    {
        string answer= "";

        return answer;
    }

    int main()
    {
        int a=5,b=24;

        //아래는 테스트 출력을 위한 코드입니다.
        cout<<getDayName(a,b);
    }


    풀이 :

    요즘에 알고리즘을 내장 라이브러리를 이용하여 문제를 푸는 것에 대하여 회의감이 들기 시작했다. 이게 과연 나에게 도움이 될 것인가? 그래서 오늘은 내장 라이브러리 없이 문제를 풀어보았다. 나의 알고리즘은 이렇다.

    1. 2016년은 윤년인지 판단
    2. 각 월의 총 요일을 저장하는 배열 생성
    3. 각 요일을 나타내는 문자열 배열 생성
    4. 입력 요일 - 1/1 일 수 구하기
    5. 일 수에 따른 요일 반환

    먼저 2016년이 윤년인지 판단하는 함수를 작성해보자. 윤년이란 보통 4년에 한 번씩 2월에 총 일수가 29일이 되는 해이다. 그러나 100년으로 나누어 떨어지면은 윤년이 아니고 400년으로 나누어 떨어지면 윤년이라는 추가적안 조건이 있는 해이다. 즉 윤년은 4로 나누어 떨어지면서 100년으로 나누어 떨어지지 않거나 400년으로 나누어 떨어지는 조건을 가지고 있는 것이다. 이것을 논리적으로 표현하면 다음과 같다.


    (4로 나누어 떨어진다 AND 100으로 나누어 떨어지지 않는다) OR (400으로 나누어 떨어진다.)


    이를 코드로 나타내보았다.


    bool is_leap_year(int year)
    {
        if ( ((0 == year%4) && (0 != year % 100)) || (0 == year % 400) )
    return true;
    else
    return false;
    }


    이제 각 월마다 요일 수를 가진 배열을 생성해보자. 제일 먼저 생각해봐야할 것은 2월달의 날이다. 2월은 윤년이면 29일 아니라면 28일의 일 수를 가지고 있다.


    const int date_of_feb = (is_leap_year(2016)) ? 29 : 28;                                     //2월 총 일 수


    이제 각 월의 요일 수를 배열로 표현해보자.


    const int date_of_month[] = {0, 31, date_of_feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //각 월의 총 일 수


    여기서 0은 인덱스는 0부터 시작하는데 월은 1부터 시작하니까 문제를 풀 때 조금 헷갈릴 가능성이 있고 무엇보다 가독성에 좋지 않았다. 그래서 이를 해결하고자 만든 내가 임의로 집어넣은 값이다.  이제 2016.1.1부터 2016.입력받은 날짜까지의 일 수를 구해보자.  코드를 보면서 설명하겠다.


    //2016.1.1 ~ 2016.a.b 까지의 일 수
    int date_interval = b-1;                        
    for(int month=1; month<a; month++){         
    date_interval += date_of_month[month];
    }


    먼저 입력 받은 일끼리 빼준다. 여기서 1은 1/1의 1일이다. 그리고 1월부터 입력받은 a월까지의 날은 1월 ~ a-1월까지의 총 일 수의 합이다. 따라서 위의 코드처럼 나타낼 수 있다. 이제 총 일 수를 구했다. 예제 5.24이라면 144일의 차이가 난다. 이제 금요일부터 144일 동안 주의 요일을 돌면 된다. 주의 요일들은 다음과 같이 나타낼 수 있다.


    const string week_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};                   //요일 뱉어내기


    그리고 주의할 것은 시작 위치는 금요일이라는 것이다. 즉 이 배열에서 5번째부터 시작해서 144일 동안 이 배열을 순회하면 된다. 이 배열을 시작 위치에서 순회하는 코드는 다음과 같다.


    week_days[ (start_week_day_index + date_interval) % 7 ];    


    다음은 나의 getDayName 함수의 전문이다.


    string getDayName(int a,int b)
    {
    const int date_of_feb = (is_leap_year(2016)) ? 29 : 28;                                     //2월 총 일 수
    const int date_of_month[] = {0, 31, date_of_feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //각 월의 총 일 수
    const string week_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};                   //요일 뱉어내기
    const int start_week_day_index = 5;          //시작 요일은 금요일 week_day에서 인덱스 5에 위치
    //2016.1.1 ~ 2016.a.b 까지의 일 수
    int date_interval = b-1;                        
    for(int month=0; month<a; month++){         
    date_interval += date_of_month[month];
    }
    //처음 시작 위치에서 date_interval 동안 week_days 배열을 돌아야 한다.
    string answer = week_days[ (start_week_day_index + date_interval) % 7 ];    

        return answer;
    }


    흠 프로그래머스에서 모든 문제에 대해 C나 C++을 지원해준다면 좋을텐데 파이썬과 자바같이 강력한 내장 라이브러리를 가진 언어들이 같이 있다보니 C++에 손이 안가는게 사실이다. 반성해야겠다.

Designed by Tistory.