简体   繁体   English

欧拉计划 #19,Python

[英]Project Euler #19, Python

I was solving Project Euler #19 :我正在解决Project Euler #19

How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?在 20 世纪(1901 年 1 月 1 日至 2000 年 12 月 31 日),有多少个星期日落在每月的第一天?

And here is the code :这是代码:

months = { "January": 31,
        "February" : 28,
        "March" : 31,
        "April" : 30,
        "May" : 31,
        "June" : 30,
        "July" : 31,
        "August" : 31,
        "September" : 30,
        "October" : 31,
        "November" : 30,
        "December" : 31}

def countingSundays():
    day = 1
    sunday_count = 0

    for year in xrange(1901,2001):

        for m in months:

            day += months[m]
            if year % 4 == 0 and m == "February":
                day += 1
            if day % 7 == 0:
                sunday_count += 1

print "Sundays:", sunday_count

The output of the program is 172 which is incorrect.程序的输出是 172,这是不正确的。 I searched the answer to be 171. So I wanted to know why am I getting the extra 1 Sunday ?我搜索的答案是 171。所以我想知道为什么我会得到额外的 1 个星期日?

You're iterating over the months dict, expecting it to iterate in the order of the months, but dicts aren't ordered, so you can get the months in the wrong order.您正在迭代months dict,期望它按月的顺序迭代,但没有对 dict 进行排序,因此您可以按错误的顺序获取月。

Since you don't actually need the month names, you can just make months a list of the month lengths instead.由于您实际上并不需要月份名称,因此您可以将months作为月份长度的列表。

You should use the datetime library, which will handled all the leap year information automatically:您应该使用datetime库,它将自动处理所有闰年信息:

from datetime import date
from collections import Counter

counter = Counter()

for year in xrange(1901, 2001):
    for month in xrange(1, 13):
        day = date(year, month, 1)
        counter[day.weekday()] += 1

print counter[6]
import time
from math import floor

"""
Gaussian algorithm to determine day of week
"""
def day_of_week(year, month, day):
    """
    w = (d+floor(2.6*m-0.2)+y+floor(y/4)+floor(c/4)-2*c) mod 7
    Y = year - 1 for January or February
    Y = year for other months
    d = day (1 to 31)
    m = shifted month (March = 1, February = 12)
    y = last two digits of Y
    c = first two digits of Y
    w = day of week (Sunday = 0, Saturday = 6)
    """

d = day
m = (month - 3) % 12 + 1
if m > 10: Y = year - 1
else: Y = year
y = Y % 100
c = (Y - (Y % 100)) / 100

w = (d + floor(2.6 * m - 0.2) + y + floor(y/4) + floor(c/4) - 2*c) % 7

return int(w)

"""
Compute the number of months starting on a given day of the week in a century
"""
def months_start_range(day,year_start,year_end):
    total = 0
    for year in range(year_start, year_end + 1):
        for month in range(1,13):
            if day_of_week(year, month, 1) == day: total += 1
    return total

start = time.time()

total = months_start_range(0,1901,2000)

elapsed = time.time() - start

print("%s found in %s seconds") % (total,elapsed)

This might you solve the problem.这可能会解决您的问题。

It took around 0.068 seconds to solve it.解决它大约需要 0.068 秒。

Here is a different approach to tackle this question这是解决这个问题的不同方法

public static void main(String[] args) {

    int k = 0;
    // String months[] = { "January", "February", "March", "April", "May", "June",
    // "July", "August", "September",
    // "October", "November", "December" };
    String Days[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
    int MonthsDdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int counter = 0;
    for (int t = 1900; t <= 2000; t++) {
        MonthsDdays[1]=28;
        if (t % 4 == 0) {
            if (t % 100 == 0)

            {
                if (t % 400 == 0)
                    MonthsDdays[1] = 29;
            } else if (t % 100 != 0)
                MonthsDdays[1] = 29;

        }

        int p = 0;
        while (p < 12) {

            for (int j = 0; j < MonthsDdays[p]; k++, j++) {
                if (k == 7)
                    k = 0;
                if (Days[k].equalsIgnoreCase("Sunday") && j == 0 && t > 1900) {
                    counter++;

                }
            }
            p++;
        }
    }
    System.out.println(counter);
}

I tried the Mathematical approach although we could use the calendar functions.尽管我们可以使用日历函数,但我尝试了数学方法。 I first calculated the math of the months to determine the relationships between the first dates of the months using the other months.我首先计算了月份的数学,以确定使用其他月份的月份的第一个日期之间的关系。 Also, for simplicity in calculating leap years, I calculated the year from March to Feb. If you want to calculate for the Jan and Feb of 1901, you can write a separate condition, and do the same to remove Jan and Feb of 2001. However, in this case, they do not really matter as they are not Sundays, so you could remove the last if condition for this specific case.另外,为了计算闰年的简单,我计算的是3月到2月的年份。如果你想计算1901年的1月和2月,你可以写一个单独的条件,同样的去掉2001年的1月和2月。但是,在这种情况下,它们并不重要,因为它们不是星期日,因此您可以删除此特定情况的最后一个 if 条件。

    # Zero is Sunday and the rest of the days are according to mod7
    # li stores the first days of the months in the year in every iteration
    # The year in initial li is 1900 but the contents are Mar-1900 to Feb-1901
    # At the end, we can check if Jan or Feb of 2001 contain a Sunday and remove if it does
    li, cnt = [4,0,2,5,0,3,6,1,4,6,2,5], 0 
    # Could also initialize li from by the same method as below, but I had already calculated those
    # cnt adds number of zeros in every iteration (the number of Sundays in every year) to its value
    # As we don't count for the year 1900 cnt=0, else initialize cnt=li.count(0)
    for year in range(1901,2001):
        if year%4==0:
            li[0]=li[8]=(li[11]+1)%7    #Set March and November to +1 value than last Feb
        else:
            li[0]=li[8]=li[11]          #Set March and November to same value as last Feb
        # The following values of other months will depend solely on their own March value
        # You can check the Math if you want to
        li[3]=li[11]=(li[0]+1)%7;li[6]=li[9]=(li[0]+2)%7;li[1]=li[4]=(li[0]+3)%7;li[2]=li[10]=(li[0]-2)%7;li[5]=(li[0]-1)%7;li[7]=(li[0]-3)%7
        cnt = cnt + li.count(0)
    # This is to remove the extra two months of the year 2001 if they bother the answer
    if li[10] == 0 or li[11] == 0:
        cnt = cnt-1
    print(cnt)

This was my first answer on StackOverflow, I hope I wrote well.这是我在 StackOverflow 上的第一个回答,希望我写得好。 ;-) ;-)

The mistakes you have:你的错误:

  1. The way you calculate leap years闰年的计算方法
  2. Dictionary does not keep the order necessarily字典不一定保持顺序
  3. You assume January 1st is Sunday你假设 1 月 1 日是星期日

The correct program would be:正确的程序是:

from collections import OrderedDict

months = OrderedDict( [("January",31),("February", 28),("March",31),
                       ("April", 30), ("May", 31), ("June", 30),
                       ("July", 31), ("August", 31), ("September", 30),
                       ("October", 31), ("November", 30), ("December", 31)] )

days = ['Tuesday','Wednesday', 'Thursday','Friday','Saturday', 'Sunday', 'Monday']

day = 0
sunday_count = 0

def isLeap(year): #https://en.wikipedia.org/wiki/Leap_year#Algorithm
  leap = True
  if year % 4 != 0:
     leap = False
  elif year % 100 != 0:
     leap = True
  elif year % 400 != 0:
     leap = False
  return leap

for year in xrange(1901,2001):
  leap = isLeap(year)

  for m in months:
      dayName = days[day%7]
      if dayName == "Sunday":
         sunday_count += 1
      #print year, m, dayName
      day += months[m]
      if leap == True and m == "February":
          day += 1

print sunday_count
# print 171

Also, some days:另外,有几天:

1901 January Tuesday
1901 February Friday
1901 March Friday
1901 April Monday
1901 May Wednesday
1901 June Saturday
1901 July Monday
1901 August Thursday
1901 September Sunday
...
import pandas as pd
from datetime import date


start = date(1901, 1, 1)
end = date(2000, 12, 31)
d = pd.date_range(start, end, freq='MS').strftime('%A')
s = pd.Series(d)

print(s.value_counts())

So I approached this problem from not a date perspective but of a counting days.所以我不是从日期的角度而是从计算天数的角度来解决这个问题的。 Here's my solution:.这是我的解决方案:。

days_1st = list()
day_counter = 1
for year in range(1900, 2001):
    for month in range(1,13):
        #Skip for year 1900 as count starts from 1901, but this still 
        #adds the days hence keeping the cycle in sync!
        if year != 1900: 
            days_1st.append(day_counter)
        if month == 4 or month == 6 or month == 9 or month == 11:
            day_counter+=30
        elif month == 2 and ((year % 100 == 0 and year % 400 == 0) or (year % 100 != 0 and year % 4 == 0)):
            day_counter+=29
        elif month == 2:
            day_counter+=28
        else:
            day_counter+=31
# mod 7 because since the day the counting started (1 Jan 1900 - 
# Monday) Every 7th day is a sunday!
days_sunday = list(filter(lambda x: x % 7 == 0, days_1st))
print(len(days_sunday)) 
A = [31,28,31,30,31,30,31,31,30,31,30,31]
sunday =0
gK = 1
for y in range(1901,2001):
    if(y %4 ==0):
        A[1] = 29
    else:
        A[1] = 28
    for m in range(len(A)):
        for d in range(1,A[m]+1):
            if(gK ==6):
                if(d==1):
                    sunday +=1

                gK =0
            else:
                gK =gK+1
print(sunday)

==>Solution in python ==>python中的解决方案

euler19.py euler19.py

normal_year = [31,28,31,30,31,30,31,31,30,31,30,31]
leap_year = [31,29,31,30,31,30,31,31,30,31,30,31]

years = [ normal_year ] * 100
for i in range(3, len(years), 4) :
    years[i] = leap_year

current_day = (0+365) % 7
sundays = 0
for y in years :
    for m in y :
        if current_day % 7 == 6:
            sundays += 1
        current_day += m%7
print (sundays)

I think I got the answer.我想我得到了答案。 I am not sure though.. your logic was right.不过我不确定……你的逻辑是对的。 But needed a little improvement.但需要一点改进。 We need to start off by counting the number of Tuesdays first as we clearly know that it was Monday on Jan 1, 1900.我们需要首先计算星期二的数量,因为我们清楚地知道今天是 1900 年 1 月 1 日的星期一。


months = { "January": 31,
        "February" : 28,
        "March" : 31,
        "April" : 30,
        "May" : 31,
        "June" : 30,
        "July" : 31,
        "August" : 31,
        "September" : 30,
        "October" : 31,
        "November" : 30,
        "December" : 31}


for month in months:
    print(months[month])


tuesday_count = 0
day = 0 
extra_days = 0
for year in range(1901, 2001):
    days_in_the_year = 0
    for month in months:
        day += months[month]
        days_in_the_year += months[month]

        if( year % 4 == 0 and month == 'February'):
                if (year % 100 != 0):
                    extra_days += 1
                    days_in_the_year += 1
                    day += 1
                elif(year % 100 ==0 and year % 400 ==0):
                    extra_days += 1
                    days_in_the_year += 1
                    day += 1
        if( (day) % 7  == 0):
                tuesday_count += 1
    print('No. of days in the year',year,'are',days_in_the_year)

print('No. of Tuesdays counted so far is  =', tuesday_count)
print('The number of extra_days because of the leap years are:',extra_days)
# print('extra_days % 7 =', '25 % 7 =', extra_days % 7)
print('So, there were', extra_days // 7, 'extra_no_of_weeks left that we haven\'t considered. After that, it\'s followed by --wed, thu, fri and sat (we don\'t need to consider that).\n So, the total number of Tuesdays are', tuesday_count+3 )

tuesday_count += 3

print('This means only 2 Sundays that have followed')
sunday_count = tuesday_count - 1
print('Since, 1901 Jan1 would be a Tuesday, we need to subract one from the total number of Sundays\n So, the total number of sundays are:', )
sunday_count=sunday_count-1
print(sunday_count)

months=[31,28,31,30,31,30,31,31,30,31,30,31]
leap=[31,29,31,30,31,30,31,31,30,31,30,31]

sundays=0
start=2
for y in range(25):
  for nonleap in range (3):
    for j in months:
      start=(start+j)%7
      if start == 0:
        sundays+=1
    
  for m in leap:
    start=(start+m)%7
    if start == 0:
      sundays+=1
print sundays

Note that the problem defines the first day of 1900 as Monday and you define the first day of 1901 as Monday.请注意,该问题将 1900 年的第一天定义为星期一,而您将 1901 年的第一天定义为星期一。

months = [31,28,31,30,31,30,31,31,30,31,30,31]

def countingSundays():
    day = 1
    sunday_count = 0

    for year in range(1900,1901):

        for m in months:
            day += m
            if (year % 4 == 0 and m == 28):
                day += 1

    for year in range(1901,2001):

        for m in months:
            day += m
            if (year % 4 == 0 and m == 28):
                day += 1
            if day % 7 == 0:
                sunday_count += 1

    return sunday_count

print ("Sundays:", countingSundays())

you have initialized the day variable to 1 but the 1st Jan 1901 is a Tuesday.您已将 day 变量初始化为 1,但 1901 年 1 月 1 日是星期二。 I made the same error ;-)我犯了同样的错误;-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM