题解:特殊日期
问题描述
给定一个日期范围(1900年1月1日至9999年12月31日),统计其中满足"年份的数字之和等于月份数字之和加上日期数字之和"的所有日期数量。
解题思路
- 遍历所有日期:从起始日期到结束日期逐日检查
- 数字和计算:分别计算年、月、日的各位数字之和
- 条件判断:比较年份数字和与月日数字和之和
- 闰年处理:正确处理2月份的天数变化
- 边界处理:确保日期递增逻辑正确
完整代码实现
public class Main {
// 平年各月份天数
static int[] month = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 闰年各月份天数(2月有29天)
static int[] monthRun = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public static void main(String[] args) {
// 起始日期:1900年1月1日
int y = 1900, m = 1, d = 1;
// 结束日期:9999年12月31日
int Dy = 9999, Dm = 12, Dd = 31;
// 当前月份天数数组指针
int[] tmpmonth;
// 满足条件的日期计数器
int count = 0;
// 主循环:逐日检查直到结束日期
while (!(y == Dy && m == Dm && d == Dd)) {
// 根据是否闰年选择月份天数数组
if (isRunyear(y)) {
tmpmonth = monthRun;
} else {
tmpmonth = month;
}
// 日期递增
d++;
// 处理月份进位
if (d > tmpmonth[m]) {
d = 1;
m++;
// 处理年份进位
if (m > 12) {
m = 1;
y++;
}
}
// 检查当前日期是否满足条件
if (isOK(y, m, d)) {
count++;
}
}
// 输出最终结果
System.out.println(count);
}
static boolean isOK(int y, int m, int d) {
return getSum(y) == getSum(m) + getSum(d);
}
static int getSum(int n) {
int sum = 0;
while (n != 0) {
int g = n % 10; // 取最后一位数字
sum += g;
n /= 10; // 去掉最后一位
}
return sum;
}
static boolean isRunyear(int n) {
// 闰年规则:
// 1. 能被400整除的是闰年
// 2. 能被4整除但不能被100整除的是闰年
return n % 400 == 0 || (n % 100 != 0 && n % 4 == 0);
}
}
代码解析
1. 数据结构
month
数组:存储平年各月份天数(2月28天)monthRun
数组:存储闰年各月份天数(2月29天)
2. 主函数逻辑
-
初始化起始日期和结束日期
-
使用while循环逐日检查:
- 根据年份判断使用平年还是闰年月份天数
- 日期递增并处理月份和年份进位
- 检查当前日期是否满足条件
3. 辅助方法
isRunyear()
:实现闰年判断逻辑getSum()
:计算任意整数的各位数字之和isOK()
:检查当前日期是否满足题目条件
复杂度分析
- 时间复杂度:O(N),其中N为日期总数(约8000年×365天≈3百万次循环)
- 空间复杂度:O(1),仅使用常数级别的额外空间
关键点说明
- 日期递增处理:正确处理月末、年末的进位逻辑
- 闰年判断:精确实现闰年规则,确保2月天数正确
- 数字和计算:通用方法处理年、月、日的数字和计算
- 边界条件:包含起始和结束日期的检查
总结
本题通过系统性地遍历所有可能日期,结合基本的数字操作和日期处理逻辑,准确统计了满足条件的日期数量。