找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2220

积分

0

好友

298

主题
发表于 14 小时前 | 查看: 9| 回复: 0

最近在开发者广场上刷到一个帖子:某大厂程序员吐槽自己人生很失败——赚了一千多万买房,结果房价下跌赔了本;孩子成绩全班倒数;媳妇整天抱怨,家里就像开了个7×24小时的报警器。

社交媒体截图:某大厂员工吐槽生活压力

我觉得这哥们不是失败,而是把压力打包成了全家共享套餐。房子这事真像线上发布,遇到回滚谁也挡不住;孩子成绩更像版本迭代,得慢慢调参;至于媳妇抱怨,先把“倾听功能”打开,比解释更有用。你说人到中年,最怕的不是跌一跤,是跌了还要强装没事。

算法题:最近时刻

那天加完班回家都快凌晨一点了,刚躺下,产品在群里给我来一句:“东哥,你那个最近时刻的算法是不是有问题?用户说早上九点和晚上九点,差了12个小时,不是最近吧?”我整个人一个激灵,这不对啊,按理说应该是0点那种跨天才容易算错,怎么九点还能玩出花来。

先说一下题目:给你一堆「HH:MM」格式的时间点,让你计算这些时间点两两之间的最小时间差,注意是“钟表上的时间”,会绕一圈。比如 ["23:59","00:00"],肉眼一看就知道最近差1分钟,不是1439分钟。

我当时写第一版的时候,想得特别简单粗暴:两个for循环,全都减一遍,绝对值取最小,完事。那会儿还沾沾自喜,觉得多朴素的写法,多有教学意义。结果线上一跑,直接超时,典型的“自己感动自己”。这种“默认写法会坑你”的体验,我在SpringBoot默认配置里踩过一大堆,惨案就不展开说了。

后来我冷静了一下,想了想菜市场买菜的场景:阿姨不会一根一根地数菜叶子,她会先拿秤,统一按斤算。时间也一样,别老盯着“09:30”、“23:59”这几个字符看,直接全换成分钟就行了——0点是0,00:01是1,01:00是60,以此类推,23:59就是23*60+59=1439。

所以第一步一定是写个小工具函数,把"HH:MM"转成分钟。那会儿我困得眼睛都睁不开了,但这个小函数还是得写完整,不然第二天肯定自己看不懂自己在干嘛。代码大概这样:

def to_minutes(t: str) -> int:
    # t 形如 "HH:MM"
    h, m = t.split(":")
    return int(h) * 60 + int(m)

这个地方其实就已经有坑了,我第一次写的时候还很中二,拆完之后忘了 int(),结果拿字符串去乘60,Python也不报错,直接给我字符串重复……然后我还奇怪结果怎么这么长一串,print了一屏幕。那一刻我就意识到:半夜写代码真的容易变成Bug生成器。

分钟有了之后就简单了,把所有时间转成分钟,然后排个序。为什么要排序?因为你要找最近的两个点嘛,直觉上肯定是“相邻的更可能近”,就像考试排队报分数,排名相邻的两个同学成绩最接近,不会跨着十几个人再去对比。

于是主函数我就这么写了一版:

from typing import List

def find_min_difference(time_points: List[str]) -> int:
    # 1. 全部转成分钟
    minutes = [to_minutes(t) for t in time_points]
    minutes.sort()

    # 2. 相邻的差值
    ans = 24 * 60  # 最大就这么多
    for i in range(1, len(minutes)):
        diff = minutes[i] - minutes[i - 1]
        if diff < ans:
            ans = diff

    # 3. 别忘了最后一个和第一个跨天那一对
    wrap_diff = 24 * 60 - minutes[-1] + minutes[0]
    ans = min(ans, wrap_diff)

    return ans

写完我自己在本地随手测了几个:

  • ["23:59", "00:00"] → 1
  • ["01:00", "01:10", "03:00"] → 10 都没问题,看起来人模狗样的。

真正的问题出在产品跟我说的那个“早九晚九”的场景。当时测试给了一组奇怪的数据:["09:00", "21:00", "09:00"]。你们看出来了吗?这个列表里有两个一模一样的时间点。我之前的写法,算完相邻差值是12小时,然后跨天那一对也是12小时,答案就一直是720分钟,完全不知道有“0分钟”这种更优解。

后来一拍脑袋:哎哟,24小时总共就1440分钟,你时间点数量如果超过1440个,那肯定至少有两个一模一样的,鸽笼原理知道吧,这就是数学老师在远方默默地对你竖起大拇指的那种场景。

于是我又给函数加了一点小心机:

def find_min_difference(time_points: List[str]) -> int:
    # 如果时间点数量超过1440,必然有重复,直接返回0
    if len(time_points) > 24 * 60:
        return 0

    minutes = sorted(to_minutes(t) for t in time_points)

    ans = 24 * 60
    for i in range(1, len(minutes)):
        diff = minutes[i] - minutes[i - 1]
        if diff == 0:
            # 提前结束,已经不可能更小了
            return 0
        if diff < ans:
            ans = diff

    wrap_diff = 24 * 60 - minutes[-1] + minutes[0]
    return min(ans, wrap_diff)

你看,逻辑其实一点都不高级:

  • 先把时间拉直成0~1439的一条线;
  • 排序之后,只看相邻的就够了;
  • 最后别忘了把这条线首尾连成一个圈,算一下“最后一个到第一个”的距离;
  • 如果时间点特别多或者出现重复,那最近时刻就是0,直接溜。

这个题最容易翻车的地方,其实就两个:第一是忘了“首尾跨天那一下”,第二是没考虑重复时间。前者会被23:59/00:00教做人,后者会被那种“列表里复制了一堆一样时间点”的测试数据拿捏。

我那天把这个版本发上去之后,测试又造了一堆妖魔鬼怪的用例,全过了。手机一扔,人往床上一躺,脑子里只有一个念头:以后再有人跟我说“这个题很简单”的时候,我都要先打个问号。

行了,最近时刻就先聊到这。如果你有类似的代码故事或想分享技术心得,欢迎来云栈社区交流。等会儿我去给咖啡续个杯,脑子又开始打转了,想起昨天有人问我“时间复杂度到底算不算挂科预警”这个问题,回头有空再吐槽。




上一篇:Claude Code Skills 高阶用法:从配置到实战的 8 个特性详解
下一篇:被Excel逼疯的班主任,我用Python Tkinter+SQLite3写了个成绩分析系统
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-16 23:20 , Processed in 0.460348 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表