欢迎光临
我们一直在努力

统计共同度过的日子数【力扣LeetCode & 每日一题】

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);
}
};

赞(0)
未经允许不得转载:171主机测评 » 统计共同度过的日子数【力扣LeetCode & 每日一题】
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址