题目重点:校验日期时间后聚合登录次数,明确格式、时区、重复事件与排序。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练输入三元组(username,YYYY-MM-DD,HH:MM:SS),按UTC日期,不接受闰秒。
- 每记录一次登录、不去重;任一非法记录拒绝本批。输出(username,date,count)按用户名再日期排序。实际格式与错误策略需确认。
解题路线
- 先检查固定格式,再用日历解析校验闰年和各月天数;正则只能查外形,不能证明2月30日合法。
- 校验完累加 (user,day) 计数。全批失败时不返回半成品;流式系统则可用 dead-letter 单独记录错误,必须明确不同合同。
- 若时间戳带时区,先转指定业务时区再提取day,不能拿UTC日期当每个用户本地日。若去重,需要稳定eventId和时间窗口,而非仅(username,time)。
- 排序用正式用户名比较规则;训练普通字符序,实际大小写/locale顺序另外规定。大量distinct用户日会占内存,可分区外存聚合。
手动走一遍
2024-02-29合法、2026-02-29非法;24:00:00按本文合同拒绝。同一用户同一天三条相同记录计3,因为没有去重合同;另一天单独行。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
import re
from datetime import datetime
from collections import Counter
def login_counts(records):
"""(username, UTC date YYYY-MM-DD, UTC time HH:MM:SS); no event dedup.
Reject the entire batch on invalid date/time; output sorted triples."""
counts = Counter()
for user, day, time in records:
if not isinstance(user, str) or not user:
raise ValueError('nonempty username required')
if not re.fullmatch(r'[0-9]{4}-[0-9]{2}-[0-9]{2}', day) or not re.fullmatch(r'[0-9]{2}:[0-9]{2}:[0-9]{2}', time):
raise ValueError('invalid date/time format')
datetime.fromisoformat(day + 'T' + time) # also rejects leap seconds
counts[user, day] += 1
return [(user, day, count) for (user, day), count in sorted(counts.items())]
复杂度
N记录、K个用户日,解析/聚合 O(N)(字段长度有界),排序 O(K log K),空间 O(K)。无限流需窗口/分区和持久化。
易错点与追问
容易失分的边界
- 只做正则。
- 静默跳过错误没告知。
- 日期按错误时区分组。
- 无eventId就擅自合并同时间记录。
继续深挖
- 如何支持本地日与夏令时?
- 迟到数据和撤回事件如何修正?
