我们需要输出 2025 年某个月的日历,格式要求为:
MON TUE WED THU FRI SAT SUN,表示星期一到星期日。MON 的 N 下方。其他日期依此类推。题目保证月份 m 在 1 到 12 之间,因此不需要考虑跨年的情况。2025 年不是闰年,2 月有 28 天。
整个问题可以分为两个核心步骤:
确定 m 月 1 日的星期
已知 2025 年 9 月 1 日是星期一(对应数字 1)。我们可以从 9 月出发,向前或向后推算到目标月份的第一天是星期几。
按格式输出日历
得到第一天是星期 w(1 表示星期一,7 表示星期日)后,按照“星期标题 + 日期分行”的要求依次输出。
我们可以用偏移天数的方法来推算:
例如:
由于月份只有 12 个,直接循环累加即可,常数时间就能完成。
MON TUE WED THU FRI SAT SUN。注意标题中的单词长度均为 3,单词间用一个空格分隔。%3d 格式(占 3 格,右对齐),这样可以天然实现“个位与星期缩写最后一个字母对齐”的效果。算法的核心是预处理每月天数和基于已知星期推算目标星期:
cpp1int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
给定 m,计算 2025 年 m 月 1 日的星期 w:
w = 1(9 月 1 日是星期一)。m > 9,则 for i = 9 to m-1: w = (w + days[i] - 1) % 7 + 1m < 9,则 for i = 8 down to m: w = ((w - days[i]) % 7 + 7) % 7随后就是按照格式输出:
i = 1 to days[m]:%3d 格式的日期;更新 w = w % 7 + 1;w == 1(下一天是星期一)或 i == days[m](本月最后一天),打印换行;否则打印一个空格,与下一个日期分隔。总体时间复杂度为 O(1),可以在极短时间内完成计算,完全满足题目的时间限制。
以下是题目提供的 C++ 参考代码,代码中已包含详细注释。
cpp1#include <cstdio> 2using namespace std; 3 4// 2025 年各月的天数(索引 1 ~ 12) 5int days[20] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 6 7int main() { 8 int m; 9 scanf("%d", &m); 10 11 // 输出星期标题 12 printf("MON TUE WED THU FRI SAT SUN\n"); 13 14 int d = days[m]; // 该月的天数 15 int w = 1; // 9 月 1 日是星期一 16 17 // 根据月份 m 推算该月 1 日的星期 w 18 if (m > 9) { 19 // 从 9 月正向推算到目标月 20 for (int i = 9; i < m; i++) 21 w = (w + days[i] - 1) % 7 + 1; 22 } else if (m < 9) { 23 // 从 9 月反向推算到目标月 24 for (int i = 8; i >= m; i--) 25 w = ((w - days[i]) % 7 + 7) % 7; 26 if (w == 0) w = 7; // 处理星期日 27 } 28 29 // 输出前导空格,使 1 号对齐到对应星期 30 for (int i = 1; i < w; i++) 31 printf(" "); // 三个空格 32 33 // 逐个输出日期 34 for (int i = 1; i <= d; i++) { 35 printf("%3d", i); // 右对齐,占 3 格 36 w = w % 7 + 1; // 星期向后推移 37 if (w == 1 || i == d) 38 printf("\n"); // 星期一或月末换行 39 else 40 printf(" "); // 普通日期后跟一个空格 41 } 42 43 return 0; 44}
%3d 会使数字在宽度为 3 的区域内右对齐。例如 1 会显示为 1(前两个空格),刚好让个位 1 位于第 3 列,与星期缩写的最后一个字母对齐。这样我们就得到了完全符合题目要求的日历输出。