Easy
题目描述
编写一个程序,计算两个日期之间的天数。
两个日期以字符串的形式给出,格式为 YYYY-MM-DD,如示例所示。
示例 1:
输入:date1 = "2019-06-29", date2 = "2019-06-30"
输出:1
示例 2:
输入:date1 = "2020-01-15", date2 = "2019-12-31"
输出:15
约束:
- 给定的日期是 1971 年到 2100 年之间的有效日期。
提示:
- 创建一个函数 f(date),计算从 1900-01-01 到 date 的天数。我们如何计算答案?
- 答案就是 |f(date1) - f(date2)|。
- 如何构造 f(date)?
- 对于从 1900 年到 year - 1 年的每一年,累加 365 天或闰年的 366 天。然后对每个月累加天数,考虑当前年份是闰年的情况,最后累加天数。
解题思路
这道题要求计算两个日期之间的天数差,根据题目提示,我们可以采用"基准日期"的思路来解决。
解题思路
核心思想是将每个日期转换为从某个固定基准日期(如 1900-01-01)开始的天数,然后计算两个天数的差值的绝对值。
具体步骤:
- 解析日期字符串:提取年、月、日信息
- 计算从基准日期的天数:
- 累加从基准年到目标年前一年的所有天数(考虑闰年)
- 累加目标年中从1月到目标月前一月的所有天数
- 加上目标月中的天数
- 判断闰年:能被4整除但不能被100整除,或者能被400整除
- 计算差值:取两个日期天数的绝对值差
这种方法的优势在于将复杂的日期计算转化为简单的数值运算,避免了直接处理跨年、跨月等复杂情况。时间复杂度主要取决于年份跨度,在给定约束下是常数级别的。
另一种思路是使用编程语言内置的日期库,但手动实现更能体现算法思维。
代码实现
class Solution {
public:
int daysBetweenDates(string date1, string date2) {
return abs(daysSince1900(date1) - daysSince1900(date2));
}
private:
bool isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int daysSince1900(string date) {
int year = stoi(date.substr(0, 4));
int month = stoi(date.substr(5, 2));
int day = stoi(date.substr(8, 2));
int days = 0;
// 累加从1900年到year-1年的天数
for (int y = 1900; y < year; y++) {
days += isLeapYear(y) ? 366 : 365;
}
// 每月天数
vector<int> monthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (isLeapYear(year)) {
monthDays[1] = 29;
}
// 累加目标年中1月到month-1月的天数
for (int m = 0; m < month - 1; m++) {
days += monthDays[m];
}
// 加上目标月中的天数
days += day;
return days;
}
};
class Solution:
def daysBetweenDates(self, date1: str, date2: str) -> int:
def is_leap_year(year):
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def days_since_1900(date):
year, month, day = map(int, date.split('-'))
days = 0
# 累加从1900年到year-1年的天数
for y in range(1900, year):
days += 366 if is_leap_year(y) else 365
# 每月天数
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if is_leap_year(year):
month_days[1] = 29
# 累加目标年中1月到month-1月的天数
for m in range(month - 1):
days += month_days[m]
# 加上目标月中的天数
days += day
return days
return abs(days_since_1900(date1) - days_since_1900(date2))
public class Solution {
public int DaysBetweenDates(string date1, string date2) {
return Math.Abs(DaysSince1900(date1) - DaysSince1900(date2));
}
private bool IsLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
private int DaysSince1900(string date) {
string[] parts = date.Split('-');
int year = int.Parse(parts[0]);
int month = int.Parse(parts[1]);
int day = int.Parse(parts[2]);
int days = 0;
// 累加从1900年到year-1年的天数
for (int y = 1900; y < year; y++) {
days += IsLeapYear(y) ? 366 : 365;
}
// 每月天数
int[] monthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (IsLeapYear(year)) {
monthDays[1] = 29;
}
// 累加目标年中1月到month-1月的天数
for (int m = 0; m < month - 1; m++) {
days += monthDays[m];
}
// 加上目标月中的天数
days += day;
return days;
}
}
/**
* @param {string} date1
* @param {string} date2
* @return {number}
*/
var daysBetweenDates = function(date1, date2) {
const d1 = new Date(date1);
const d2 = new Date(date2);
return Math.abs((d2 - d1) / (1000 * 60 * 60 * 24));
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(1) | 由于年份范围限定在1971-2100年,最多迭代200年,是常数级别 |
| 空间复杂度 | O(1) | 只使用了常数级别的额外空间存储变量 |
相关题目
- . Count Days Spent Together (Easy)