2409. 统计共同度过的日子数
网页链接
力扣LeetCode
力扣LeetCode & 每日一题,完成每日打卡,即可获得力扣积分。获得相应数量的积分,能在【力扣商店】,换取相应奖品!助力每日有题做,丰盈积分日益多!
题目描述
Alice 和 Bob 计划分别去罗马开会。
给你四个字符串 arriveAlice、leaveAlice、arriveBob 和 leaveBob。Alice 会在日期 arriveAlice 到 leaveAlice 之间在城市里(日期为闭区间),而 Bob 在日期 arriveBob 到 leaveBob 之间在城市里(日期为闭区间)。每个字符串都包含
5
5
5 个字符,格式为 "MM-DD",对应着一个日期的月和日。
请你返回 Alice 和 Bob 同时在罗马的天数。
你可以假设所有日期都在同一个自然年,而且不是闰年。每个月份的天数分别为:[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]。
输入描述
四个表示日期的字符串,格式均为 "MM-DD":arriveAlice、leaveAlice、arriveBob、leaveBob。
输出描述
返回 Alice 和 Bob 同时在罗马的天数。
示例 1
输入:
arriveAlice = "08-15", leaveAlice = "08-18", arriveBob = "08-16", leaveBob = "08-19"
输出:
3
解释:
Alice 从
8
8
8 月
15
15
15 号到
8
8
8 月
18
18
18 号在罗马。Bob 从
8
8
8 月
16
16
16 号到
8
8
8 月
19
19
19 号在罗马,他们同时在罗马的日期为
8
8
8 月
16
16
16、
17
17
17 和
18
18
18 号。所以答案为
3
3
3。
示例 2
输入:
arriveAlice = "10-01", leaveAlice = "10-31", arriveBob = "11-01", leaveBob = "12-31"
输出:
0
解释:
Alice 和 Bob 没有同时在罗马的日子,所以我们返回
0
0
0。
数据范围
- 所有日期的格式均为 "MM-DD"。
- Alice 和 Bob 的到达日期都早于或等于他们的离开日期。
- 题目测试用例所给出的日期均为非闰年的有效日期。
解题思路
本题是日期转序数 + 区间交集问题。Alice 和 Bob 各自在罗马的日期是一个闭区间,两人同时在罗马的天数就是两个闭区间的交集长度。关键在于把 "MM-DD" 格式的日期转换成一年中的第几天,从而把日期比较转化为整数比较。
1. 日期转一年中的第几天
非闰年每月天数固定为:
[
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
]
[31,28,31,30,31,30,31,31,30,31,30,31]
[31,28,31,30,31,30,31,31,30,31,30,31] 用前缀和数组 P 预处理每个月之前累计的天数:
P
[
0
]
=
0
,
P
[
1
]
=
31
,
P
[
2
]
=
59
,
…
,
P
[
12
]
=
365
P[0]=0,\\quad P[1]=31,\\quad P[2]=59,\\quad \\dots,\\quad P[12]=365
P[0]=0,P[1]=31,P[2]=59,…,P[12]=365 其中 P[m-1] 表示前 m-1 个月的总天数。因此对日期 "MM-DD":
f
(
MM-DD
)
=
P
[
m
−
1
]
+
d
f(\\text{MM-DD}) = P[m-1] + d
f(MM-DD)=P[m−1]+d 即可得到该日期在一年中的序号(从 1 开始)。
例如 "08-15" 转为
P
[
7
]
+
15
=
212
+
15
=
227
P[7] + 15 = 212 + 15 = 227
P[7]+15=212+15=227。
2. 字符串比较的巧妙之处
由于输入日期格式固定为 "MM-DD",月份和日期都是零填充的两位数字,因此字符串的字典序与日期的时间先后完全一致。于是:
- 交集左端点 = max(arriveAlice, arriveBob)(字典序较大者,即较晚到达的日期);
- 交集右端点 = min(leaveAlice, leaveBob)(字典序较小者,即较早离开的日期)。
不需要先转整数再比较,可以直接用 std::max / std::min 对字符串取并得到交集端点。
3. 计算交集天数
设交集区间为
[
l
,
r
]
[l, r]
[l,r],则同时在天数的天数为:
r
−
l
+
1
r – l + 1
r−l+1 若
r
<
l
r < l
r<l(两人没有重叠日期),则结果为负数,需要与
0
0
0 取最大值:
max
(
r
−
l
+
1
,
0
)
\\max(r – l + 1,\\ 0)
max(r−l+1, 0)
对应代码:
int l = f(max(a1, b1));
int r = f(min(a2, b2));
return max(r – l + 1, 0);
4. 边界说明
- 题目保证 arrive <= leave,因此单个区间合法;
- 若两人区间不相交,则
l
>
r
l > r
l>r,公式自然得到非正数,取 max(…,0) 返回 0; - 同一天到达并同一天离开时,交集可能只有 1 天,公式同样正确。
5. 复杂度分析
- 日期转换:
O
(
1
)
O(1)
O(1)(字符串长度固定为 5); - 字符串比较:
O
(
1
)
O(1)
O(1); - 总时间复杂度
O
(
1
)
O(1)
O(1),空间复杂度O
(
1
)
O(1)
O(1)。
总结
先用前缀和数组把 "MM-DD" 转成一年中的第几天。利用零填充格式下字典序与日期先后一致的性质,直接对字符串取 max/min 得到两个闭区间的交集端点,再用 r – l + 1 计算天数并与 0 取最大值。整体是常数时间的日期区间求交问题。
代码内容
class Solution {
static constexpr int P[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
int f(string s) {
int m = (s[0] – '0') * 10 + s[1] – '0';
int d = (s[3] – '0') * 10 + s[4] – '0';
return P[m – 1] + d;
}
public:
int countDaysTogether(string a1, string a2, string b1, string b2) {
int l = f(max(a1, b1));
int r = f(min(a2, b2));
return max(r – l + 1, 0);
}
};

实现100%通过率-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261026191216-6adfa61015a7f-220x80.gif)

