🎄Advent of Code 2025 挑战全手写代码 Day 2 - 礼品店
第二天题目 Gift Shop,难度简单(1.5 星 ⭐),主要考察字符串处理和枚举。
📖 题目速览

题目地址:https://adventofcode.com/2025/day/2
北极基地的礼品店数据库被小精灵搞乱了,输入了一堆无效的商品 ID。我们需要在给定的多个数字范围内(例如 11-22, 95-115),找出所有符合特定“重复模式”的“无效 ID”。
Part 1: 找出由重复两次的数字序列组成的 ID(如 123123)。
Part 2: 找出由重复至少两次的数字序列组成的 ID(如 123123123 或 111)。
例如:
55(5重复) -> Part 1 & 2 无效 ❌123123(123重复) -> Part 1 & 2 无效 ❌111(1重复三次) -> Part 1 有效 ✅,但 Part 2 无效 ❌101-> 有效 ✅0101-> 题目规定无前导零,不是 ID
任务:找出所有范围内符合条件(无效)的 ID 并求和。
💡 解题思路 (Python 🐍)
今天的核心是判断一个数字是否符合“重复模式”。
-
解析输入:输入是一长串逗号分隔的范围
start-end,先用split处理成(start, end)元组列表。 -
暴力枚举 (Part 1 & 2):
因为我们是直接提交答案而不是在线实时运行,对时间的要求可以放宽。最直接的方法就是遍历范围内每一个数字,转成字符串判断。def _is_invalid_1(self, num: int) -> bool: s = str(num) length = len(s) # Part 1: 长度必须是偶数,且前半段等于后半段 if length % 2 != 0: return False return s[:length//2] == s[length//2:]Part 2 规则升级(重复次数 >= 2),我的解法是枚举所有可能的“子串长度”
delta,检查数字是否由该子串重复构成。def _is_invalid_2(self, num: int) -> bool: s = str(num) half = len(s) // 2 # 尝试所有可能的循环节长度 for delta in range(1, half + 1): if len(s) % delta == 0: # 将字符串切分为长度为 delta 的片段 parts = [s[i:i+delta] for i in range(0, len(s), delta)] # 检查所有片段是否相同 if all(p == parts[0] for p in parts[1:]): return True return False
✨ 代码复盘 & 优化思考
虽然上面的解法能过,但作为算法爱好者,不得不反思一下:
-
当前的“笨”解法:
我是老老实实遍历了 range 里的每一个数字去检查。如果题目给的范围是1到100亿,这种 O ( N ) O(N) O(N) 的解法直接原地爆炸 💥。这就好比为了找“四叶草”,把整片草地的每一根草都拔起来看一遍。 -
更优的“生成式”思路:
其实符合AB...AB...这种重复模式的数字是非常稀疏的。
与其“检查”,不如“构造”。- 比如要找 6 位以内的目标数,我只需要枚举
1到999(作为前半段 S S S)。 - 然后把
S
S
S 拼成
S
S
SS
SS (如
123->123123)。 - 直接看这个 S S SS SS 在不在题目给的 range 里就行了。
- 这种方法复杂度瞬间降到 O ( N ) O(\sqrt{N}) O(N),效率提升几个数量级!🚀
- 比如要找 6 位以内的目标数,我只需要枚举
虽然 Day 2 用“笨”方法可以解,但保持对复杂度的敏感度是必要的!💪
完整代码:访问 github
Happy Coding! 今天也要继续冲榜!🚀

698

被折叠的 条评论
为什么被折叠?



