项目Euler#19,Python

时间:2015-06-14 14:26:04

标签: python

我正在解决Project Euler#19:

在二十世纪的第一个月(1901年1月1日至2000年12月31日),有多少个星期日下降?

以下是代码:

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

程序的输出是172,这是不正确的。 我搜索的答案是171。 所以我想知道为什么我得到额外的1周日?

14 个答案:

答案 0 :(得分:3)

你正在迭代months dict,期望它按照月份的顺序进行迭代,但是不会对dicts进行排序,因此你可以按错误的顺序获取月份。 / p>

由于您实际上并不需要月份名称,因此您只需将months列为月份长度即可。

答案 1 :(得分:1)

您应该使用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]

答案 2 :(得分:1)

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)

这可能会解决问题。

解决它需要大约0.068秒。

答案 3 :(得分:1)

这里是解决此问题的另一种方法

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);
}

答案 4 :(得分:0)

你犯的错误:

  1. 计算闰年的方式
  2. 字典不保留订单
  3. 您认为1月1日是星期日
  4. 正确的计划是:

    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
    

    另外,有些日子:

    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
    ...
    

答案 5 :(得分:0)

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

答案 6 :(得分:0)

所以我从日期的角度来看这个问题,而不是计算天数。 这是我的解决方案:

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

答案 7 :(得分:0)

尽管我们可以使用日历功能,但我尝试了数学方法。 我首先计算了月份的数学运算,以确定使用其他月份的月份的第一天之间的关系。另外,为简化计算leap年,我计算了从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)

这是我对StackOverflow的第一个答案,希望我写得不错。 ;-)

答案 8 :(得分:0)

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)

答案 9 :(得分:0)

==> Python解决方案

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)

答案 10 :(得分:0)

我想我得到了答案。不过,我不确定。您的逻辑是否正确。但是需要一点改进。首先,我们需要首先计算星期二的数量,因为我们清楚地知道这是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)

答案 11 :(得分:0)

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

答案 12 :(得分:0)

请注意,问题将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())

答案 13 :(得分:0)

您已将day变量初始化为1,但1901年1月1日是星期二。我犯了同样的错误;-)