Daily Algorithm - Day 18

105·2025년 1월 8일
0

Daily Algorithm

목록 보기
19/30

Counting Sundays

You are given the following information, but you may prefer to do some research for yourself.

  • 1 Jan 1900 was a Monday.
  • Thirty days has September,
    April, June and November.
    All the rest have thirty-one,
    Saving February alone,
    Which has twenty-eight, rain or shine.
    And on leap years, twenty-nine.
  • A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.

    How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?

20세기에 매월 1일이 일요일인 경우는 몇 번인지 구하는 문제이다.
내가 생각한 구현 방식은 다음과 같다.

  1. n년도가 윤년인지 판별해주는 함수를 작성
  2. 각 날짜를 시작일부터 며칠 째인지로 표현해주는 함수를 작성.
    (ex. 1900년 1월 20일 = 20, 1901년 2월 4일 = 400)
  3. 1900년 1월 1일이 월요일이니 총 일수를 7로 나누었을 때 나머지가 1이면 월요일, 0이면 일요일이다. 이 점과 반복문을 이용해서 모든 날짜에 대해 매월 1일이 일요일인 경우를 구한다.

우선 윤년의 조건을 구하자면 1901~2000 사이에서 100의 배수가 2000년 뿐인데 이는 400의 배수이므로 윤년. 즉, 4의 배수만 모두 구하면 되지만 확장성을 위해 모든 조건을 추가해주자.

//Python

def is_leap(n):
    if n % 4 == 0 and (n % 100 != 0 or n % 400 == 0):
        return True
    else:
        return False 

그리고 다음은 날짜를 총 며칠 째인지 표현해주는 함수이다.

def total_days (start_year, year, month, day):
    month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    
    result = 0
    
    # (start_year-1)년 ~ (year-1)년 까지 일수
    for y in range (start_year-1, year):
        result += 365
        if is_leap(y):
            result += 1
            
    # (year)년 1월 ~ (month-1)월 까지 일수        
    for m in range (1, month):
        result += month_days[m-1]
        if (m == 2 and is_leap(year)):
            result += 1
    
    # (month)월 1일 ~ (day)일 까지의 일수
    result += day
    
    return result

start_year에 시작년도를, year, month, day에 각각 년, 월, 일을 입력하면 총 며칠째인지를 출력해준다.

이제 반복문을 통해 답을 구할 시간이다.

def find_first_sundays(start_year, end_year):
    first_sundays = 0
    for year in range(start_year, end_year + 1):
        for month in range(1, 13):
            if (total_days(start_year, year, month, 1)) % 7 == 0:
                first_sundays += 1
    return first_sundays
        
print(find_first_sundays(1901,2000))

>>> 171 #correct

범위가 바뀌는 것을 상정해서 함수로 만들어 두긴 했는데, 생각해보니 매년 1월 1일의 요일이 바뀌기 때문에 시작년도가 바뀐다면 활용하기 어려울 것 같다... 재사용되는 변수를 오기하지 않도록 짠 것에 의의를 두자.

그리고 번외로 파이썬의 datetime 모듈을 이용하면 아주 간단하게 구현이 가능하다.

from datetime import date, timedelta

start_date = date(1901, 1, 1)
end_date = date(2000, 12, 31)

first_sundays = 0
current_date = start_date

while current_date <= end_date:
    
    # 매월 1일이 일요일이면 count
    if current_date.day == 1 and current_date.weekday() == 6:  # 사실 1일인건 확인할 필요가 없지만
        first_sundays += 1
    
    # 다음 달로 이동
    next_month = current_date.month % 12 + 1
    next_year = current_date.year + (current_date.month // 12)
    current_date = date(next_year, next_month, 1)

print(first_sundays)

>>> 171

오늘은 여기까지.
-2025.01.08-

profile
focus on backend

0개의 댓글