【发布时间】:2018-04-11 16:21:31
【问题描述】:
我不确定我的解决方案是否合理(ans. 171) - Project Euler Q.19,因为我很难理解模运算,并且不确定我的方法是否正确。 ..我在尝试获得将 0 作为键而不是 1 到星期一以在哈希表中引用的等效性时遇到了麻烦。问题是;
- 1900 年 1 月 1 日是星期一。
- 30 天有九月、四月、六月和十一月。其余的都有三十一,仅存二月,二月有二十八,雨
或闪耀。闰年是二十九岁。- 闰年出现在任何能被 4 整除的年份,但不会出现在一个世纪,除非它能被 400 整除。
在第 20 个月的第一天有多少个星期天 世纪(1901 年 1 月 1 日至 2000 年 12 月 31 日)?
所以我所做的是将天数总和从 1 开始(参考哈希表中的天数)并在找到星期日的总和后减去 1,因为当总天数可被 3 整除时,将其除以 0 会导致问题和 6(3:星期三,6:星期日)。我怎么能通过使用 0 作为星期一的参考来做到这一点?
import java.util.*;
public class p19 {
public static void main(String[] args) {
Hashtable<Integer, String> days = new Hashtable<Integer, String>();
days.put(1, "Monday");
days.put(2, "Tuesday");
days.put(3, "Wednesday");
days.put(4, "Thursday");
days.put(5, "Friday");
days.put(6, "Saturday");
days.put(7, "Sunday");
Hashtable<Integer, String> months = new Hashtable<Integer, String>();
months.put(1, "January");
months.put(2, "February");
months.put(3, "March");
months.put(4, "April");
months.put(5, "May");
months.put(6, "June");
months.put(7, "July");
months.put(8, "August");
months.put(9, "September");
months.put(10, "October");
months.put(11, "November");
months.put(12, "December");
int min, max;
min = 1900;
max = 2000;
String[][] arr = new String[12 * (max - min + 1)][];
// Total days starts at 1 to make modular arithmetic easier when accounting for days
// (i.e., 1 Monday, 2 Tuesday, etc.) and since the first day, hence, 0th day on 1 Jan 1900 is Monday.
for (int year = min, index = 0, totalDays = 1; year <= max; year++) {
for (int month = 1; month <= 12; month++, index++) {
arr[index] = new String[numberOfDays(month,year)];
int sum = 1;
System.out.println(months.get(new Integer(month)) + " " + year);
for (int day = 1; day <= numberOfDays(month, year); day++, totalDays++) {
if (totalDays % 7 == 0) {
arr[index][day - 1] = days.get(new Integer((totalDays % 7 + 7) % 365));
}
else {
arr[index][day - 1] = days.get(new Integer((totalDays % 7) % 365));
}
if (sum > 7) {
System.out.println();
sum = 1;
}
System.out.print(totalDays + ":= " + arr[index][day - 1] + ", " + day + " | ");
sum++;
}
System.out.println("\n");
}
}
int count = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i][0] == "Sunday") {
count++;
}
}
// Subtract 1 from count since the total days were overstated by 1 before inititallizing array
System.out.println("Number of Sundays that fell on the first of the month from: 1/Jan/1901 - 31/Dec/2000: " + (count - 1));
}
public static int numberOfDays (int month, int year) {
int days = 0;
switch (month) {
case 7:
case 4:
case 6:
case 11:
days = 30;
break;
case 2:
if (isLeapYear(year)) {
days = 29;
}
else {
days = 28;
}
break;
default: days = 31;
break;
}
return days;
}
public static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
}
【问题讨论】:
-
我不得不承认我不明白你的做法。恕我直言,您可以选择 1901 年的第一个星期日并在每个日期上加上 +7,然后检查日期是否为 YYYY-MM-01。或者你从 1901-2000 年,从 1 到 12 月,生成日期 y/m/01 并检查它是否是星期日。所以你试图在没有日期/时间库的情况下解决它。但是为什么你需要月份名称?工作日的名称是什么?在不使用日期/时间库的情况下,为什么要从 1 开始索引天数和月份,而这很难通过模运算得到正确的结果?
-
顺便说一句。这是一种 shell 方法,但使用日期函数:
for x in {0..36525..7}; do date -d "6 Jan 1901 +$x days" | grep "So 1\." ; done | wc -l171 和这里的另一个方法(在我的语言环境中也是星期天)cnt=0; for y in {1901..2000}; do for m in {1..12}; do dow=$(date -d "$y-$m-01" +%a); if [[ $dow == "So" ]] ; then ((++cnt)); fi; done; done; echo $cnt结果:171 -
直到现在我才知道日期/时间库,谢谢。而且我很难想象,所以我制作了一个数组来打印 LOL。
-
好吧,作为模运算的练习,这不是浪费时间。 Java 日期时间库 (java.util.Date) 引入了一个接口,其中
getMonth返回 0 表示 1 月,这与其他函数配合得很好,但当然每个人都希望 6 指代 6 月。我想新的替代品避免了这个陷阱,几乎每个初学者都会进入这个陷阱,甚至有经验的程序员偶尔也会进入这个陷阱。 :) -
非常感谢,非常感谢!
标签: java math number-theory modular-arithmetic