LeetCode 1185. 一周中的第几天
题目描述

题意分析
输入日、月、年,返回对应星期的英文名称。题目保证日期有效且位于 1971 到 2100 年,并给出基准:1971 年 1 月 1 日是星期五。只要算出目标日期比基准晚多少天,再按七天一周期平移即可。
解法一:累计天数与闰年计数
核心思路
[!blue]
令
days为从 1971 年 1 月 1 日到目标日期已经经过的天数,基准当天记为零。把它分为三部分:此前完整年份的天数、目标年份中此前完整月份的天数,以及本月已经过去的day - 1天。完整年份共有
year - 1971个,先按每年 365 天计数,再补上其中闰年的额外一天。公历闰年满足“能被四整除且不能被一百整除,或者能被四百整除”。因此截至年份y的闰年个数是y/4 - y/100 + y/400,这里均为整数除法:先计四的倍数,再扣掉整百年份,最后加回整四百年份。用截至year - 1的数量减去截至 1970 的数量,就得到本次需要补入的整年闰日数。月份用平年长度表累加目标月之前的月份。若目标年是闰年,而且目标月在二月之后,再补上一天;一月、二月不能提前补,否则会把尚未经过的二月二十九日算进去。目标日自身不算已经过去,所以最后加入的是
day - 1。星期数组按周日到周六排列,下标为零到六,基准星期五对应下标五。目标星期下标就是
(days + 5) % 7。日期范围保证days非负,不需要处理负数取模;所有累计天数也都在普通整数范围内。
解题步骤
- 准备七个英文星期名称与十二个月的平年天数。
- 计算完整年份的 365 天部分,再用闰年计数差补入闰日。
- 累加目标月之前的完整月份;目标年为闰年且月份大于二时再加一天。
- 加上
day - 1,返回星期数组中(days + 5) % 7对应的名称。
代码实现
class Solution {
public String dayOfTheWeek(int day, int month, int year) {
String[] weekdays = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
};
int[] monthDays = {
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
};
int lastYear = year - 1;
int leapYears = lastYear / 4 - lastYear / 100 + lastYear / 400
- (1970 / 4 - 1970 / 100 + 1970 / 400);
int days = (year - 1971) * 365 + leapYears + day - 1;
for (int m = 1; m < month; m++) {
days += monthDays[m - 1];
}
if (month > 2 && (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))) {
days++;
}
return weekdays[(days + 5) % 7];
}
}
func dayOfTheWeek(day, month, year int) string {
weekdays := [...]string{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
}
monthDays := [...]int{
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
}
lastYear := year - 1
leapYears := lastYear/4 - lastYear/100 + lastYear/400 - (1970/4 - 1970/100 + 1970/400)
days := (year-1971)*365 + leapYears + day - 1
for m := 1; m < month; m++ {
days += monthDays[m-1]
}
if month > 2 && (year%400 == 0 || (year%4 == 0 && year%100 != 0)) {
days++
}
return weekdays[(days+5)%7]
}
复杂度分析
- 时间复杂度:$O(1)$。完整年份用公式一次计算,月份循环最多执行十一次。
- 空间复杂度:$O(1)$。星期表与月份表的大小均固定。
关键点总结
[!green]
- 从已知星期的基准日起累计经过天数,再对七取模。
- 整年闰日只统计到目标年前一年,本年闰日按目标月份另外处理。
- 基准当天偏移为零,所以本月贡献为
day - 1。
解法对比
逐年累加也能求出经过天数,但需要逐年判断闰年。这里用整除公式直接统计完整年份的闰日,只保留最多十一次的月份累加,仍能清楚区分年、月、日三部分。
易错点总结
[!yellow]
- 只判断年份能否被四整除,会把不能被四百整除的整百年份误算为闰年。
- 整年计数统计到目标年,会与本年的月份累计重复。
- 闰年一月、二月不能统一加一天,闰日此时尚未完整经过。
- 使用
day而非day - 1,或忘记基准星期五的偏移五,都会使结果错位。
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!