2
\$\begingroup\$

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)?

day_names = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
month_names = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
 'October', 'November', 'December']
month_days_common = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
month_to_days = dict(zip(month_names, month_days_common))
def is_leap(year):
 """return True if a year is leap. False otherwise."""
 if (year % 4) == 0:
 if (year % 100) == 0:
 if (year % 400) == 0:
 return True
 else:
 return False
 else:
 return True
 else:
 return False
def get_date_day_names(end_year):
 """return a list of tuples containing day name, day, month, year from 1900 to end_year(exclusive)."""
 start_year = 1900
 total = 0
 all_day_names = []
 all_months1 = []
 all_months2 = {}
 year_month_times_number_of_days = []
 final_dates = []
 for year in range(start_year, end_year):
 count = 0
 while count < 12:
 all_months1.append((year, month_names[count]))
 count += 1
 for year in range(start_year, end_year):
 if is_leap(year):
 total += 366
 else:
 total += 365
 for i in range(total):
 all_day_names.append(day_names[i % 7])
 for year, month in all_months1:
 if is_leap(year):
 if month == 'February':
 all_months2[(year, month)] = 29
 else:
 all_months2[(year, month)] = month_to_days[month]
 else:
 all_months2[(year, month)] = month_to_days[month]
 for date, number_of_days in all_months2.items():
 for i in range(number_of_days):
 year_month_times_number_of_days.append((date, i + 1))
 date_day_name = list(zip(all_day_names, year_month_times_number_of_days))
 for date_item in date_day_name:
 final_dates.append((date_item[0], date_item[1][1], date_item[1][0][1], date_item[1][0][0]))
 return final_dates
def count(day_name, day_of_the_month, end_year):
 """returns count of a given day from 1901 to end_year(exclusive)"""
 final_dates = []
 dates_1900_to_end_year = get_date_day_names(end_year)
 for date in dates_1900_to_end_year:
 if date[-1] != 1900 and date[0] == day_name and date[1] == day_of_the_month:
 final_dates.append(date)
 return len(final_dates)
if __name__ == '__main__':
 print(count('Sunday', 1, 2001))
asked Jul 19, 2019 at 3:24
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

whole algorithmic change => \$O(n)\$

Your existing algorithm is quite confusing. Perhaps instead you could try a simpler structure such as:

from datetime import date
def num_sundays_on_first_of_month(year1, year2):
 num_sundays = 0
 for i in range(year1, year2+1):
 for j in range(1, 13):
 if date(i, j, 1).weekday() == 6:
 num_sundays += 1
 return num_sundays
if __name__ == '__main__':
 print(num_sundays_on_first_of_month(1901,2000))

This code is much more readable and far briefer. It makes effective use of the datetime module and its date objects. It works by looping through every month between year1 and year2 inclusive and counting if it is a Sunday.

This runs at \$O(n)\$ time where \$n = year2 - year1\$

answered Jul 19, 2019 at 9:26
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Yeah, you have a point, I sometimes overcomplicate stuff. The whole point was trying not to use modules and I did it for fun I guess. \$\endgroup\$ Commented Jul 19, 2019 at 9:48
  • \$\begingroup\$ If you don't. Want to use modules, The date class is a very simple object that can easily be added to your program. \$\endgroup\$ Commented Jul 19, 2019 at 23:55

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.