1. 题目解析与需求理解
"L1-024 后天 - 5分"这道题目看似简单,实则考察了编程基础中的日期计算和边界处理能力。题目要求我们根据给定的日期(星期几),计算出后天的星期数。比如今天是周三,后天就是周五;如果是周六,后天就是下周一。
这类日期循环计算在实际开发中非常常见,比如:
- 日程提醒系统中计算未来某天的星期
- 工作日计算器跳过周末
- 周期性任务调度(如每周三、五执行)
注意:星期计数方式在不同地区可能不同,国内通常将周日作为一周的第7天,而西方部分国家将周日作为第1天。本题默认采用国内习惯(1-7对应周一到周日)。
2. 核心算法设计
2.1 基础算法实现
最直接的思路就是对当前星期数加2,然后处理溢出情况:
python复制def get_day_after_tomorrow(today):
return today + 2 if today + 2 <= 7 else (today + 2) % 7
这个实现看似简单,但存在两个潜在问题:
- 当today + 2正好等于7时(如today=5),取模会得到0而非7
- 没有对输入参数进行有效性校验
2.2 边界条件处理
更健壮的实现应该考虑以下边界情况:
- 输入验证(1-7范围)
- 周日(7)的后天是周二(2)
- 周六(6)的后天是周一(1)
改进后的算法:
python复制def get_day_after_tomorrow(today):
if not 1 <= today <= 7:
raise ValueError("输入必须为1-7的整数")
return (today + 1) % 7 + 1
这个版本通过先加1取模再加1的技巧,完美解决了所有边界情况:
- today=5(周五): (5+1)%7+1=7→周日
- today=6(周六): (6+1)%7+1=1→周一
- today=7(周日): (7+1)%7+1=2→周二
3. 完整实现与测试
3.1 Python实现
python复制def get_day_after_tomorrow(today):
"""
计算后天是星期几
参数:
today (int): 当前星期几,1-7表示周一到周日
返回:
int: 后天的星期数
异常:
ValueError: 当输入不在1-7范围内时抛出
"""
if not isinstance(today, int) or not 1 <= today <= 7:
raise ValueError("输入必须为1-7的整数")
return (today + 1) % 7 + 1
# 测试用例
test_cases = {
1: 3, # 周一 → 周三
2: 4, # 周二 → 周四
3: 5, # 周三 → 周五
4: 6, # 周四 → 周六
5: 7, # 周五 → 周日
6: 1, # 周六 → 周一
7: 2, # 周日 → 周二
}
for today, expected in test_cases.items():
result = get_day_after_tomorrow(today)
assert result == expected, f"测试失败: {today}→{result}, 应为{expected}"
print("所有测试通过!")
3.2 C语言实现
c复制#include <stdio.h>
#include <assert.h>
int get_day_after_tomorrow(int today) {
if (today < 1 || today > 7) {
fprintf(stderr, "错误: 输入必须为1-7的整数\n");
return -1;
}
return (today + 1) % 7 + 1;
}
int main() {
int test_cases[][2] = {
{1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 1}, {7, 2}
};
for (int i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); i++) {
int today = test_cases[i][0];
int expected = test_cases[i][1];
int result = get_day_after_tomorrow(today);
assert(result == expected);
}
printf("所有测试通过!\n");
return 0;
}
4. 常见问题与优化
4.1 输入处理技巧
在实际应用中,我们可能需要处理字符串形式的星期输入:
python复制def parse_weekday(input_str):
"""
将各种形式的星期输入转换为数字(1-7)
支持: "周一"/"星期一"/"monday"/"mon"/"1"等形式
"""
weekday_map = {
# 中文
"一": 1, "1": 1, "周一": 1, "星期一": 1,
"二": 2, "2": 2, "周二": 2, "星期二": 2,
# ... 其他星期类似
"日": 7, "7": 7, "周日": 7, "星期日": 7,
# 英文
"mon": 1, "monday": 1,
"tue": 2, "tuesday": 2,
# ... 其他星期类似
"sun": 7, "sunday": 7
}
input_str = input_str.strip().lower()
return weekday_map.get(input_str, -1)
4.2 性能优化
虽然这个简单的计算不需要太多优化,但在高频调用场景下可以考虑:
- 使用查找表代替计算:
python复制_LOOKUP = [0, 3, 4, 5, 6, 7, 1, 2] # 索引0不用,1-7对应结果
def get_day_after_tomorrow_fast(today):
return _LOOKUP[today]
- 在C/C++中使用内联函数或宏:
c复制#define GET_DAY_AFTER_TOMORROW(today) (((today) + 1) % 7 + 1)
4.3 国际化考虑
如果需要支持不同地区的星期起始日,可以增加配置参数:
python复制def get_day_after_tomorrow(today, week_start=1):
"""
支持自定义一周起始日
week_start: 1表示周一作为第一天(中国习惯)
0表示周日作为第一天(西方习惯)
"""
if week_start == 1: # 中国习惯
return (today + 1) % 7 + 1
else: # 西方习惯
return today % 7 + 2 if today % 7 + 2 <= 7 else (today % 7 + 2) % 7
5. 实际应用扩展
5.1 工作日计算
计算N个工作日后的日期(跳过周末):
python复制def add_workdays(start_day, n):
"""
计算n个工作日后的星期
参数:
start_day: 起始星期(1-7)
n: 要增加的工作日天数
返回:
结果星期数和总共过去的天数
"""
result_day = start_day
total_days = 0
for _ in range(n):
total_days += 1
result_day = (result_day) % 7 + 1
# 跳过周末
while result_day in (6, 7): # 周六或周日
total_days += 1
result_day = (result_day) % 7 + 1
return result_day, total_days
5.2 周期性任务调度
实现类似"每周三、五执行"的调度器:
python复制class WeeklyScheduler:
def __init__(self, target_days):
"""
target_days: 目标星期几列表,如[3,5]表示周三和周五
"""
self.target_days = set(target_days)
def is_target_day(self, today):
return today in self.target_days
def next_target_day(self, today):
"""
返回下一个目标日距离今天的天数
"""
day = today
for i in range(1, 8):
day = day % 7 + 1
if day in self.target_days:
return i
return 7 # 理论上不会执行到这里
6. 测试与验证
完整的单元测试应该包含以下测试用例:
python复制import unittest
class TestDayAfterTomorrow(unittest.TestCase):
def test_normal_cases(self):
self.assertEqual(get_day_after_tomorrow(1), 3) # 周一 → 周三
self.assertEqual(get_day_after_tomorrow(3), 5) # 周三 → 周五
self.assertEqual(get_day_after_tomorrow(6), 1) # 周六 → 周一
def test_weekend_boundary(self):
self.assertEqual(get_day_after_tomorrow(5), 7) # 周五 → 周日
self.assertEqual(get_day_after_tomorrow(7), 2) # 周日 → 周二
def test_invalid_input(self):
with self.assertRaises(ValueError):
get_day_after_tomorrow(0)
with self.assertRaises(ValueError):
get_day_after_tomorrow(8)
with self.assertRaises(ValueError):
get_day_after_tomorrow("abc")
if __name__ == "__main__":
unittest.main()
7. 其他语言实现示例
7.1 JavaScript实现
javascript复制function getDayAfterTomorrow(today) {
if (!Number.isInteger(today) || today < 1 || today > 7) {
throw new Error("输入必须为1-7的整数");
}
return (today + 1) % 7 + 1;
}
// 测试
const testCases = [
[1, 3], [2, 4], [3, 5], [4, 6], [5, 7], [6, 1], [7, 2]
];
testCases.forEach(([input, expected]) => {
const result = getDayAfterTomorrow(input);
console.assert(result === expected,
`测试失败: ${input}→${result}, 应为${expected}`);
});
console.log("所有测试通过!");
7.2 Java实现
java复制public class DayAfterTomorrow {
public static int getDayAfterTomorrow(int today) throws IllegalArgumentException {
if (today < 1 || today > 7) {
throw new IllegalArgumentException("输入必须为1-7的整数");
}
return (today + 1) % 7 + 1;
}
public static void main(String[] args) {
int[][] testCases = {
{1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 1}, {7, 2}
};
for (int[] testCase : testCases) {
int today = testCase[0];
int expected = testCase[1];
int result = getDayAfterTomorrow(today);
assert result == expected :
String.format("测试失败: %d→%d, 应为%d", today, result, expected);
}
System.out.println("所有测试通过!");
}
}
8. 算法复杂度分析
虽然这个简单算法的复杂度是O(1),但我们可以从几个维度分析:
-
时间复杂度:
- 基础计算:O(1)
- 带输入验证:O(1)
- 最坏情况(异常输入):O(1)
-
空间复杂度:
- 基础版本:O(1)
- 查找表优化版:O(7)→O(1)
-
实际性能考量:
- 在Python中,函数调用开销可能比计算本身更大
- 对于超高频调用(如百万次/秒),可以考虑使用查找表或内联函数
- 在大多数实际应用中,这个计算不会成为性能瓶颈
9. 相关算法扩展
9.1 计算任意天数后的星期
Zeller公式可以计算任意日期是星期几:
python复制def zeller(year, month, day):
"""
Zeller公式计算星期几
返回0-6对应周日到周六
"""
if month < 3:
month += 12
year -= 1
K = year % 100
J = year // 100
h = (day + (13*(month+1))//5 + K + K//4 + J//4 + 5*J) % 7
return h
9.2 处理闰年
计算两个日期之间的天数需要考虑闰年:
python复制def is_leap_year(year):
"""判断是否为闰年"""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
def days_in_month(year, month):
"""返回某年某月的天数"""
if month == 2:
return 29 if is_leap_year(year) else 28
elif month in [4, 6, 9, 11]:
return 30
else:
return 31
10. 工程实践建议
-
错误处理:
- 对于不可信输入(如用户输入),应该进行严格验证
- 提供有意义的错误信息,而不仅仅是返回-1或抛出异常
-
API设计:
- 考虑提供多种输入格式支持(数字、字符串等)
- 支持不同的星期起始日配置
- 提供反向查询功能(如"前天")
-
文档规范:
- 使用docstring明确函数用途和参数
- 提供典型使用示例
- 注明可能的异常情况
-
测试覆盖:
- 边界测试(1和7)
- 非法输入测试(0, 8, 非数字等)
- 类型测试(字符串、浮点数等)
-
性能考量:
- 对于高频调用场景,可以使用缓存或查找表
- 在性能敏感场景,考虑使用位运算替代取模
python复制# 使用位运算的优化版本(仅适用于模7)
def get_day_after_tomorrow_bit(today):
return (today + 1) - 7 * ((today + 1) // 7)