Skip to content

Commit 26dd9b2

Browse files
committed
docs: upate algorithm-stories.md
1 parent ffc0bc9 commit 26dd9b2

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

docs/algorithm-stories.md

+59-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
- [“红色眼睛与褐色眼睛”谜题](#红色眼睛与褐色眼睛谜题)
66
- [找出剩下的一个数](#找出剩下的一个数)
7+
- [2199年7月2日是星期几?](#2199年7月2日是星期几?)
78

89
## “红色眼睛与褐色眼睛”谜题
910
从前,有个小岛上只住着和尚。有些和尚的眼睛是红色的,而另一些则是褐色的。红色眼睛的和尚受到诅咒,如果得知自己的眼睛是红色的,那么当晚 12 点必须自行了断,无一例外。
@@ -55,4 +56,61 @@ for (int i = 0; i < 100; ++i) {
5556
System.out.println("最后剩下的数是:" + res);
5657
```
5758

58-
如果将集合的 100 个数值累加,会得到 5050。依次从 5050 减去数组中的 99 个数值,最后的数就是没能保存到数组的那个剩余数值。也许很多读者想到了与此相近的算法。即使没有得到正确答案也不用失望,因为真正应该感到失望的人是那些没能找到答案后轻易选择放弃、想要直接查看正确答案的人。
59+
如果将集合的 100 个数值累加,会得到 5050。依次从 5050 减去数组中的 99 个数值,最后的数就是没能保存到数组的那个剩余数值。也许很多读者想到了与此相近的算法。即使没有得到正确答案也不用失望,因为真正应该感到失望的人是那些没能找到答案后轻易选择放弃、想要直接查看正确答案的人。
60+
61+
## 2199年7月2日是星期几?
62+
先公布答案吧,2199年7月2日是星期二。其实可以靠运气蒙一下,准确率是 1/7。要想真正求出正确答案,过程并不简单。也许有些读者会自己设计精妙算法求出正确答案,但我还是想通过约翰•康威教授的“末日”算法进行说明。
63+
64+
末日算法虽然不是“游戏”,但在聚会中能够引起初次见面的异性的好奇。因此,为不少“花花公子”踏入数学殿堂做出了很大贡献。例如,“美丽的女士,求告诉我您的生日,让我猜猜是星期几。”“请您随便说一个年份,我会猜出当年的情人节是星期几”。虽然听起来比较肉麻,不过这样就能一下子吸引对方的注意。
65+
66+
康威教授的末日算法执行环境就是我们今天使用的“公历”环境。
67+
68+
首先,先理清楚**什么是闰年**。闰年是年份能被 4 整除但不能被 100 整除,或者能被 400 整除的年份。闰年 2 月有 29 天,而平年 2 月是 28 天。
69+
70+
```java
71+
// 判断是否是闰年
72+
boolean isLeapYear(int year) {
73+
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
74+
}
75+
```
76+
77+
康威末日算法的运行原理非常简单。为了判断不同日期的星期,算法中首先**设立一个必要的“基准”**。然后,**根据星期以 7 为循环的原则和对闰年的考虑**,计算日期对应的星期。
78+
79+
平年时,将 2.28 日设置为“末日”;到了闰年,将 2.29 日设置为“末日”。只要知道了特殊年份(e.g. 1900 年) “末日”的星期,那么根据康威算法即可判断其它日期的星期。
80+
81+
我们都知道,星期以 7 为循环,所以与“末日”以 7 的倍数为间隔的日期就和“末日”具有相同的星期。利用这个原理,先记住每个月中总是与“末日”星期相同的一个日期,即可快速算出结果。
82+
83+
每个月与“末日”具有相同星期的一天分别是:
84+
85+
```
86+
4.4、6.6、8.8、10.10、12.12、9.5、5.9、7.11、11.7、3.7
87+
```
88+
89+
只需要记住 4、6、6、10、12 这几个月与日的数字相同,然后是 9.5、5.9、7.11、11.7,这几个是对称的,还有一个是 3.7。是不是很容易记住?
90+
91+
好了,那么我们**只要知道当年的“末日”是星期几,就可以推算出当年的任何一天是星期几了**
92+
93+
举个例子吧。2003 年的“末日”是星期五,我们推算一下那一年的圣诞节的星期。由于 2003 年“末日”是星期五,所以 12 月 12 日也是星期五(我们上面记住了每个月与“末日”具有相同星期的一天),那么 `12+7*2=26`,12 月 26 日也是星期五,所以 12 月 25 日是星期四。
94+
95+
那么问题来了,**怎么才能知道某一年的“末日”是星期几呢**
96+
97+
这种情况下,需要记住“末日”的星期每跨 1 年就会加 1,若遇到闰年就会加 2。
98+
99+
例如,1900 年的“末日”是星期三,那么 1901 年的“末日”是星期四(+1),1902 年的“末日”是星期五(+1),1903 年的“末日”是星期六(+1),而 1904 年(闰年)的“末日”是“星期一”(+2)。
100+
101+
就是说,我们记住了 1900 年“末日”是星期三,就可以推算出其它年份的“末日”是星期几了。
102+
103+
这样一个个推算还是很麻烦,可能一不小心就推错了。为此,康威教授贴心地给我们提供了如下形式的列表。
104+
105+
```
106+
6, 11.5, 17, 23, 28, 34, 39.5, 45, 51, 56, 62, 67.5, 73, 79, 84, 90, 95.5
107+
```
108+
109+
就是说,1900 年“末日”是星期三,那么 1906,1917,1923... “末日”也是星期三, 11.5 表示 1911 年的“末日”是星期二(-1),而1912 年的“末日”是星期四(+1)。记住这个列表,我么就能够胜场所有 20 世纪年份的“末日基准”了。
110+
111+
如果一个美丽的姑娘说“我的生日是 1992.9.13” 时,我们可以马上说出当天的星期。既然康威列表有 90 这个数字,表示 1990 年的“末日”也是星期三,那么 1901 年(平年)“末日”是星期四(+1),1902 年(闰年)“末日”是星期六(+2),所以 9.5/9.12 也是星期六,1992.9.13 就是星期日。
112+
113+
不过,**年份跨越世纪时,康威列表就会失去作用**
114+
115+
116+

0 commit comments

Comments
 (0)