繁体   English   中英

欧拉计划 #19,Python

[英]Project Euler #19, Python

我正在解决Project Euler #19

在 20 世纪(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 个星期日?

您正在迭代months dict,期望它按月的顺序迭代,但没有对 dict 进行排序,因此您可以按错误的顺序获取月。

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

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

这可能会解决您的问题。

解决它大约需要 0.068 秒。

这是解决这个问题的不同方法

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

尽管我们可以使用日历函数,但我尝试了数学方法。 我首先计算了月份的数学,以确定使用其他月份的月份的第一个日期之间的关系。 另外,为了计算闰年的简单,我计算的是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 上的第一个回答,希望我写得好。 ;-)

你的错误:

  1. 闰年的计算方法
  2. 字典不一定保持顺序
  3. 你假设 1 月 1 日是星期日

正确的程序是:

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

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

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)

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

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

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

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

暂无
暂无

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

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