103. 时间问题(暴力枚举)
1. 2017年蓝桥杯省赛 - 日期问题(困难)
标签:2017
暴力
枚举
省赛
1.1 题目描述
小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
1.2 输入描述
一个日期,格式是 " A A / B B / C C AA/BB/CC AA/BB/CC" ( 0 ≤ A , B , C ≤ 9 ) (0≤A,B,C≤9) (0≤A,B,C≤9)。
1.3 输出描述
输出若干个不相同的日期,每个日期一行,格式是 " y y y y − M M − d d yyyy−MM−dd yyyy−MM−dd"。多个日期按从早到晚排列。
1.4 输入输出样例
示例:
输入
txt
02/03/04
输出
txt
2002-03-04
2004-02-03
2004-03-02
1.5 运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
2. 解题思路
本题核心思路是枚举 + 校验合法性 + 排序去重,具体步骤如下:
-
解析日期三元组: 输入为
AA/BB/CC
,分别代表三个部分,可能是年/月/日的任意排列; -
枚举三种排列方式:
AA/BB/CC
→年/月/日
CC/AA/BB
→月/日/年
CC/BB/AA
→日/月/年
-
年份补全规则:
60 ≤ year ≤ 99
→ 补为19xx
00 ≤ year ≤ 59
→ 补为20xx
year = { 1900 + y , if y ≥ 60 2000 + y , if y < 60 \text{year} = \begin{cases} 1900 + y, & \text{if } y \geq 60 \\ 2000 + y, & \text{if } y < 60 \end{cases} year={1900+y,2000+y,if y≥60if y<60
-
日期合法性校验:
- 月份范围:
1~12
- 日期范围:根据月份和是否闰年判断(尤其是2月)
is_leap ( y ) = { True , if y m o d 400 = 0 True , if y m o d 4 = 0 and y m o d 100 ≠ 0 False , otherwise \text{is\_leap}(y) = \begin{cases} \text{True}, & \text{if } y \bmod 400 = 0 \\ \text{True}, & \text{if } y \bmod 4 = 0 \text{ and } y \bmod 100 \ne 0 \\ \text{False}, & \text{otherwise} \end{cases} is_leap(y)=⎩ ⎨ ⎧True,True,False,if ymod400=0if ymod4=0 and ymod100=0otherwise
- 月份范围:
-
排序并去重输出。
txt
|------2002-03-04------|------2004-02-03------|------2004-03-02------>
3. 代码实现
python
# 02/03/04
# 年/月/日, 2002-03-04 => 2002-03-04
# 月/日/年, 02-03-2004 => 2004-02-03
# 日/月/年, 02-03-2004 => 2004-03-02
# 读取输入,形如 02/03/04
# a, b, c = map(int, '02/03/04'.split('/'))
a, b, c = map(int, input().split('/'))
# 月份与天数对应关系
dc = {
1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30,
7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31
}
# 补全年份:60-99为19xx,0-59为20xx
def hs_1(y):
if y >= 60:
y += 1900
else:
y += 2000
return y
# 判断闰年
def hs_2(y):
if y % 400 == 0:
return True
elif y % 4 == 0 and y % 100 != 0:
return True
else:
return False
# 创建日期列表
s = []
for y, m, d in [
[a, b, c], # a年/b月/c日
[c, a, b], # a月/b日/c年
[c, b, a], # a日/b月/c年
]:
y = hs_1(y) # 转换年份
if 1 <= m <= 12: # 月份范围正确
max_day = dc[m] # 获取该月最大天数
if m == 2 and hs_2(y): # 闰年 2 月处理
max_day = 29
if 1 <= d <= max_day: # 日期范围正确
s.append([y, m, d])
# 排序并去重输出
s.sort()
k = 0
print('{}-{:02}-{:02}'.format(s[0][0], s[0][1], s[0][2]))
for i in range(len(s)):
if s[k] != s[i]: # 对输出结果进行去重
k = i
print('{}-{:02}-{:02}'.format(s[i][0], s[i][1], s[i][2]))
4. 复杂度分析
- 时间复杂度: O ( 1 ) O(1) O(1),枚举固定的3种排列方式,对每种情况进行常数时间的合法性判断和排序。
- 空间复杂度: O ( 1 ) O(1) O(1), 最多存储3个合法日期,使用常数空间。