Leap Year
给你一个公历年份 year。如果这一年是闰年,也就是有 2 月 29 日,则返回 true,否则返回 false。
如果一个年份能被 4 整除,它就是闰年。但能被 100 整除的年份不是闰年,除非它也能被 400 整除。
函数
- yearinteger
- 要检查的年份
- 返回值boolean
- 如果这一年有 2 月 29 日,则为 true;否则为 false
约束条件
1 ≤ year ≤ 106
示例
- 输入
- year = 2024
- 输出
- true
- 解释
2024能被4整除,而且不是世纪年,所以它是闰年。
- 输入
- year = 1900
- 输出
- false
- 解释
1900能被4整除,但也能被100整除,且不能被400整除,因此适用世纪例外:不是闰年。
- 输入
- year = 2000
- 输出
- true
- 解释
2000能被100整除,因此不符合条件;但它也能被400整除,所以又符合条件了。它是闰年。
提示
逐个打开提示,每个都会多透露一点。
除以
4后余数为0是第一条规则。哪些年份不符合这条规则?世纪年会打破这个规则,而
400的倍数又会打破世纪年的规则。每个400的倍数也是100和4的倍数,因此检查的顺序会决定答案。先检查能否被
400整除,然后检查能否被100整除,接着检查能否被4整除,并以第一个匹配的规则为准。也可以将它们合并:能被 4 整除且不能被 100 整除,或者能被 400 整除。
题解
每条规则都需要一次取余,因此要做三次整除检查。陷阱在于顺序:在 2000 年这个既是世纪年、又是 400 的倍数的年份上,规则会相互冲突。先测试最具体的规则,或者写一个用括号保留例外情况的表达式。
按从最具体到最不具体的顺序检查规则
思路
能被 4 整除的年份是闰年,能被 100 整除则取消这一规则,能被 400 整除则取消对前一规则的取消。每个 400 的倍数都是 100 的倍数,而每个 100 的倍数都是 4 的倍数,因此由匹配的最具体规则决定结果。
先检查 400,再检查 100,然后检查 4,并在首次匹配时返回。2000 在第一次检查时就符合条件,1900 在第二次检查时符合条件,2024 在第三次检查时符合条件。没有匹配任何条件的年份不能被 4 整除,因此是平年。
算法
- 如果
year % 400 == 0,返回true。 - 如果
year % 100 == 0,返回false。 - 如果
year % 4 == 0,返回true。 - 否则返回
false。
def isLeapYear(year):
if year % 400 == 0:
return True
if year % 100 == 0:
return False
if year % 4 == 0:
return True
return False一个布尔表达式
思路
把规则理解为成为闰年的两种情况:能被 4 整除且不是世纪年,或者能被 400 整除。这句话可以写成 (year % 4 == 0 and year % 100 != 0) or year % 400 == 0。
2024 符合第一种情况。1900 和 2000 都是世纪年,因此都不符合第一种情况;只有 2000 符合第二种情况,因为 1900 % 400 的结果是 300。将规则分组为能被 4 整除,并且(不是世纪年或能被 400 整除),对每一年都会得到相同的结果。
算法
- 计算
year % 4 == 0 and year % 100 != 0:能被 4 整除且不是整百年。 - 计算
year % 400 == 0。 - 如果任一部分成立,则返回
true。
def isLeapYear(year):
# Every 4th year, except centuries, except every 400th year.
return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
易错点和边界情况
- 只检查
year % 4 == 0。对于1901到2099之间的所有年份,这都是对的,因此这个 bug 不容易被发现;但对于1900和2100,结果是错的。 - 在 if 链中先检查
100,再检查400。世纪年份检查会在400的检查运行之前,对2000返回false。 - 漏掉能被 4 整除这一部分。
year % 100 != 0 or year % 400 == 0会把2023判定为闰年,因为2023不是世纪年份。 - 本来要用余数,却用了
year / 4。除法会告诉你4能装下多少次;余数则会告诉你它能否整除。
常见问题3
检查闰年的时间复杂度是多少?
时间和空间复杂度均为 O(1):无论是哪一年,最多进行三次取余运算和几次比较。
为什么 1900 年不是闰年,而 2000 年是?
这两个都是世纪年,可以被 100 整除,通常会因此被判定为平年。2000 也可以被 400 整除,而这条规则优先于世纪年的规则。1900 除以 400 后余 300,所以仍然是平年。
为什么会有世纪规则?
一个太阳年约为 365.2422 天。每 4 年增加一个闰日,平均长度就变为 365.25 天,每 400 年大约多出 3 天。在每 4 个世纪年中跳过其中 3 个闰日,就能减去这些天,使平均长度达到 365.2425 天,让日历与季节保持同步。
相似题目
运用相同思路的题目。做两三道,才能真正掌握一种模式。
def isLeapYear(year):
# 在这里编写代码测试 #1
测试 #2
测试 #3
参数
year = 2024
预期输出
true