Advent of Code 2025 挑战全手写代码 Day 5 - 餐厅

🎄Advent of Code 2025 挑战全手写代码 Day 5 - 餐厅


Welcom back! 今天题目 Cafeteria 难度简单(一星 ⭐),主要考察排序集合区间合并等知识点。

📖 题目速览

题目地址:adventofcode.com/2025/day/5

我们终于进入了传说中的"秘密餐厅"!但是,因为新的库存管理系统崩溃了,精灵大厨们分不清哪些食材是新鲜 (Fresh)的,哪些是变质(Spoiled)的。为了吃上饭,我们得帮他们修 Bug。

Part 1:点在区间内(Point in Interval)

输入包含两部分:

  1. 一组新鲜食材的 ID 区间 (例如 3-5, 10-14)。
  2. 一组现有库存的 ID (例如 1, 5, 8)。

规则很简单:如果一个库存 ID 落在任何一个新鲜区间内,它就是新鲜的。 任务:统计现有库存中有多少个 ID 是新鲜的。

💡 Part 1 优化思路

最直接的做法是双重循环:遍历每个 ID,再遍历每个区间检查。复杂度是 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( N × M ) O(N \times M) </math>O(N×M)。

但其实我们可以预先对区间进行排序 (按起始位置升序排列),然后对每个 ID 使用二分查找或者将区间合并后查找。这样可以将时间复杂度从线性降到对数!

不过对于 Part 1 的数据量其实很小,暴力法也没问题。


Part 2:区间并集的长度(Length of Union of Intervals)

精灵们为了省事,想知道总共有多少个整数 ID 被认为是新鲜的。 也就是说,我们要计算所有给定的新鲜区间的并集 包含了多少个整数。 在这一部分,现有库存的 ID 就没有用了,我们只需要(已经排好序的)新鲜食材的 ID 区间

例如: [3, 5][4, 6] 合并后是 [3, 6],包含 3, 4, 5, 6 共 4 个数。

🚫 我的踩坑时刻 这题我一开始写了个 Bug,在合并区间时:

python 复制代码
if start - target[1] <= 1:
    target = target[0], end  # ❌ 错误写法!

我直接把当前区间的 end 赋给了合并后的终点。 但这忽略了一种情况:如果当前区间完全被包含 在目标区间内(例如 target=[1, 10], current=[3, 5]),这样做会导致合并后的区间反而变小了(变成了 [1, 5])!这导致得到的结果比正确结果要小很多!

✅ 正确写法应该是取最大值:

python 复制代码
target = target[0], max(target[1], end)

就差这一个 max,让我调试了好半天... 😅


💻 为什么不用 Set?

为什么不直接把所有区间里的数都塞进一个 set 里去重,最后求 len(set)? 对于小数据量这当然没问题。但如果区间范围非常大(例如 1-1000000000),用 Set 会造成极大的内存空间浪费,因为我们实际上并不需要知道每个ID的具体数值。

区间合并算法 的优势在于: 它只处理区间的"端点",与区间内的具体数值跨度无关。 无论区间是 1-5 还是 1-100亿,对算法来说都只是处理两个数字。

  • 时间复杂度 : <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( N log ⁡ N ) O(N \log N) </math>O(NlogN),主要花在排序上。
  • 空间复杂度 : <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( 1 ) O(1) </math>O(1) 。

✨ 核心代码 (Python)

python 复制代码
def solve_part2(ranges):
    # 1. 必须按起始位置排序!
    ranges.sort(key=lambda x: x[0])
    
    out = 0
    target = ranges[0]

    for idx in range(1, len(ranges)):
        start, end = ranges[idx]

        # 2. 判断是否重叠或相连(离散整数,差1也算连着)
        if start - target[1] <= 1:
            # 3. 核心:取最大的结束位置
            target = target[0], max(target[1], end)
        else:
            # 4. 结算上一段区间长度
            out += target[1] - target[0] + 1
            target = start, end

    # ‼️别忘了加上最后一段
    out += target[1] - target[0] + 1
    return out

今天这题虽然也是 1 星难度,但很好地考察了贪心排序的思想,是 LeetCode 56 (Merge Intervals) 的变种。

完整代码:访问 github

Happy Coding! 今天也要继续冲榜!🚀

相关推荐
源代码•宸21 分钟前
大厂技术岗面试之谈薪资
经验分享·后端·面试·职场和发展·golang·大厂·职级水平的薪资
alvin_200541 分钟前
python之OpenGL应用(二)Hello Triangle
python·opengl
铁蛋AI编程实战1 小时前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
晚霞的不甘1 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
jiang_changsheng1 小时前
RTX 2080 Ti魔改22GB显卡的最优解ComfyUI教程
python·comfyui
喵叔哟1 小时前
06-ASPNETCore-WebAPI开发
服务器·后端·c#
0思必得02 小时前
[Web自动化] Selenium处理滚动条
前端·爬虫·python·selenium·自动化
Charlie_lll2 小时前
力扣解题-移动零
后端·算法·leetcode
沈浩(种子思维作者)2 小时前
系统要活起来就必须开放包容去中心化
人工智能·python·flask·量子计算
2301_790300962 小时前
Python数据库操作:SQLAlchemy ORM指南
jvm·数据库·python