ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python刷LeetCode全套解答:从环境搭建到模板库的实战指南

2026/10/8 11:55:02 拓冰建站 浏览量
Python刷LeetCode全套解答:从环境搭建到模板库的实战指南 简介这是一份面向 Python 开发者和算法学习者的 LeetCode 全套题解资料涵盖从数组、链表、树等基础数据结构到动态规划、回溯搜索等经典算法适合正在准备技术面试或希望系统提升算法能力的读者按题刷练。压缩包共 1160 个文件包含 580 个 Markdown 题目解读文档与 579 个 Python 解答脚本另有 gitignore 配置文件整体约 544KB体量精简但题目覆盖完整便于本地检索和对照学习。目前已有 587 人浏览学习。通过学习这套 Python 版解答可以直观理解每道题的解题思路、代码实现与复杂度要点熟悉 Python 内置容器及标准库的灵活运用配合 md 笔记与 py 源码对照能在反复练习中巩固排序、搜索、图论等核心算法从题目分析到代码验证形成完整闭环为面试手写代码和日常开发中的问题拆解打下扎实基础。1. 「leetcode全套解答python版本」到底值不值得你花一个周末你从 GitHub 上搜「leetcode全套解答python版本」大概率会看到一个没人整理的仓库几千个 .py 文件按题号堆在目录里点开一跑有的缺 import有的只写方法没写测试还有不少解法是「看起来对、提交就超时」的版本。这就是我第一次拿到所谓的全套题解时面对的场面——答案是真的能直接用的没几个。这套东西真正的价值不在于「正确答案」本身而在于你把仓库下载下来、逐题跑通、按自己的习惯重写一遍的过程。这篇笔记写给两类人正准备系统刷 LeetCode 的 Python 新手以及把题解当教材研究「为什么这么写」的面试者。你会得到一套能复现的本地环境、常用数据结构的 Python 惯用写法还有十几条我自己踩过的坑。2. 搭好本地刷题环境版本、虚拟环境与「能提交」的测试骨架2.1 用 3.10 解释器建虚拟环境版本选择和 PATH 的坑先把版本定下来。LeetCode 官方支持 Python 3.8 以上我的建议是直接装 3.10 或 3.12。很多「全套解答」里用到了|做类型合并、match语句这些是 3.10 才有的语法如果你本机已经装了 3.8也不是跑不了但你会频繁遇到「这行语法我明明见过但不知道为什么报错」的尴尬。装 Python 本身没什么好说的Windows 去官网下载安装包记得勾选 Add Python to PATHmacOS 建议用brew install python3.12Linux 用 apt 或源码编译都行网上 python 安装教程一大堆我只提醒一句——装完先确认python3 --version和which python3别让系统里某个旧版本先截胡了 PATH这一步能省掉后面一半的环境变量配置问题。然后是虚拟环境。我见过太多人把全套题解 clone 下来之后直接用系统 Python 裸跑结果依赖互相打架最后怀疑是题目太难的——其实只是环境脏了。常见做法是给这套题解单独开一个 venvcd leetcode-solutions # 进入题解仓库目录 python3 -m venv .venv # 创建虚拟环境 source .venv/bin/activate # 激活环境Windows 用 .venv\Scripts\activate pip install --upgrade pip # 升级 pip避免旧版本解析依赖出错这段命令干了三件事在当前目录建一个叫.venv的隔离环境激活它让后续的pip和python都指向这个环境再升一下pip本身以免老版本在装依赖时出现奇怪的 SSL 或版本解析问题。把依赖装进虚拟环境而不是全局等你要换库的版本或者删掉整个仓库重来都不会污染系统。如果项目里有requirements.txt就pip install -r requirements.txt没有的话大部分纯算法题解其实只需要标准库你甚至可以什么都不装直接跑这也是 Python 刷题相对其他语言最省事的地方。本地调试我习惯配合 VS Code配置好 Python 解释器路径后可以直接单步看变量比盲猜print高效得多。2.2 用 unittest 搭一套测试骨架让题解从「能跑」变「敢提交」全套解答的价值在于验证。你从仓库里拉下来的代码能不能提交、边界条件对不对不是你人眼能看出来的。你需要一个统一的测试骨架把每一道题变成「输入几个参数 → 断言输出」。我一般会在仓库根目录建一个tests/目录每题对应一个测试文件用unittest而不是 pytest原因很简单LeetCode 本地跑题用unittest零依赖格式和题目给的示例输入天然对应。import unittest from typing import List from solutions.two_sum import two_sum # 假设题解放在 solutions/ 下 class TestTwoSum(unittest.TestCase): def test_basic(self): self.assertEqual(two_sum([2, 7, 11, 15], 9), [0, 1]) def test_same_value_twice(self): self.assertEqual(two_sum([3, 3], 6), [0, 1]) def test_no_answer(self): self.assertIsNone(two_sum([1, 2, 3], 7)) if __name__ __main__: unittest.main()参数说明two_sum接收一个列表和一个目标值返回下标对找不到时返回None。第一个用例覆盖普通情况第二个专门测「两个相同值互为答案」的边界第三个测无解分支——这三类用例基本能把你搜到的「全套解答」里那种只写 happy path 的代码打回原形。跑法也简单python -m unittest tests.test_two_sum或者直接在文件里执行python tests/test_two_sum.py前提是你当前在仓库根目录且solutions和tests都能被 Python 找到如果缺包就在根目录建一个空的__init__.py或者把solutions的路径加到PYTHONPATH里。有了这套骨架你每做一道题就是把题解粘进来、跑一遍、看哪些用例挂了然后逼自己去把挂掉的那行看懂。这里多说一句很多人 clone 了题解仓库之后第一反应是当成小说从头读到尾这基本等于没读。正确姿势是先跑题解仓库自带的测试如果有没有就自己按上面的模板套跑挂了再读那段代码。你迟早会发现网上流传的所谓全套解答真正能过的可能不到六成——有的用了官网上不存在的函数有的是「看起来对但边界一碰就碎」。所以测试骨架不是可选项是必选。2.3 核心代码模式与 ACM 模式输入输出处理的两种姿势LeetCode 默认给你一个类和方法你只管填方法体这叫核心代码模式。但周赛、笔试或者某些面试环节是 ACM 模式不给类直接给标准输入要你自己解析和输出。我见过不止一个把题解背得很熟的人一遇到「第一行 N第二行 N 个数」就卡住问题从来不是算法而是输入输出处理。import sys def main(): data sys.stdin.read().strip().split() # 一次性读入全部输入按空白切分 if not data: return n int(data[0]) # 第一个 token 是数组长度 nums list(map(int, data[1:1 n])) # 切片取出 n 个数并转 int # 对 nums 做处理... print( .join(map(str, result))) if __name__ __main__: main()逻辑说明先把整个 stdin 读进来按空白切分成 token 列表再按题意取前 N 个转成 int这样不管输入是换行分隔还是空格分隔都成立。代码里的data[1:1 n]是习惯写法第一个数字是数组长度后面才是数组元素切到1 n能恰好截掉多余的部分。很多 ACM 题要跑多组输入那就改成一个while循环每次读取一段处理输出直到 EOF。这个模板会陪你经历很多场笔试建议直接存成常用代码片段。另一个常见坑是输出格式末尾不要多打空格 .join(...)已经帮你处理好「最后一个元素后面不跟空格」的问题千万别用for循环逐个print再加空格。3. 数据结构题的 Python 惯用写法链表、栈、哈希表如何少写十几行这一章是重点。同样是 Python写起来可以优雅十倍也可以难看到让面试官皱眉。LeetCode 的 Python 题解质量高不高看得不是算法多新奇而是你有没有用对 Python 的内置能力和「省代码」的惯用写法。3.1 链表题dummy 节点与「先存 next 再改指针」的骨架链表是 Python 刷题里最微妙的——因为 Python 没有指针所有「指针操作」全靠对象引用。反转链表这道题迭代写法用的是三指针def reverse_list(head): prev None # 已反转部分的头 cur head # 当前待处理的节点 while cur: nxt cur.next # 先存下一步防止链表断开 cur.next prev prev cur cur nxt return prev逻辑说明prev表示已经反转好的那段链表的头cur是当前要反转的节点nxt先保存下一步要去哪。因为第三行cur.next prev会把cur.next改写如果不先存nxt链表就断了后面彻底遍历不下去。这个套路在链表题里出现频率极高删除节点、两两交换、反转局部链表全都是这套「先存 next 再改指针」的骨架。但链表题真正拉开差距的是 dummy 节点。凡是要动头节点的操作——比如删除头节点、在头节点前插入——不引入 dummy 你就会写出一堆if head is None的特殊分支。我的惯例是只要涉及「可能改 head 本身」先dummy ListNode(0, head)最后直接return dummy.next这样头节点就变成一个普通节点参与处理代码少写三分之一更重要的是你不会漏掉「删掉头节点」这种边界情况。递归也能写反转链表但 Python 递归深度限制摆在那链表一长就 RecursionError所以我一般只在面试官特意要求「试试递归」时才用平时默认迭代。3.2 单调栈739 每日温度这类题栈里存索引别存值单调栈是个被讲烂了但非常值得掌握的技巧。拿「每日温度」举例给你每天温度要返回往后第几天才出现更高的温度。暴力是 O(n²)面试官基本不会满意用单调栈可以让每个元素至多出入栈一次整体 O(n)。def daily_temperatures(temperatures): n len(temperatures) res [0] * n stack [] for i, t in enumerate(temperatures): while stack and temperatures[stack[-1]] t: # 栈顶遇到更高温度 j stack.pop() res[j] i - j # 答案是索引差即天数 stack.append(i) return res参数说明stack里存的是下标不是温度值。为什么存下标因为结果要求的是「间隔天数」需要两个位置相减如果你存温度弹出后还得去找这个温度在哪个位置凭空多一次查找。这是本题的关键心法单调栈里存的是「还没找到下一个更大值的下标」当前温度通过temperatures[stack[-1]]取。循环结束时栈里剩下的下标都对不到更高温度保持初始化的0正好。把这题的思路抽象出来就是「下一个更大元素」这一类问题看到题目里出现「下一个更大/更小」「左边第一个比它大」这种描述第一反应就应该是单调栈而不是堆。我自己刷题早期每次遇到都暴力匹配然后超时后来才明白这类题的优化本质是「让每个元素被比较的次数尽可能少」而不是「提前把答案算好」。栈的入栈出栈恰好保证了每个元素只被比较几次这才是单调栈比暴力快的根本原因。3.3 哈希表与 Counter两数之和的边遍历边建表哈希表在 Python 里就是字典两数之和最直白的解法是def two_sum(nums, target): seen {} for i, v in enumerate(nums): if target - v in seen: # 之前已经出现过匹配值 return [seen[target - v], i] seen[v] i # 记录当前值的位置供后面的元素配对 return None逻辑说明关键在「边遍历边建字典」而不是「先把字典建完再遍历」。你在处理第 i 个元素时字典里只有前 i 个元素的信息所以target - v in seen一定不会和当前元素自己配对——这行代码同时解决了去重和查找两个问题。如果先建完字典再查就必须额外处理「同一个下标不能用两次」的边界。另外这个写法天然是「第一次遇到目标就返回」满足题目「只需返回一组答案」的要求。Counter 是collections模块里被严重低估的一个类。遇到「判断两个词是不是异位词」「统计窗口内字符频率」这类题手写字典累加代码又长又容易漏初始值from collections import Counter def can_construct(ransom_note, magazine): a Counter(ransom_note) b Counter(magazine) return a b aCounter可以直接做集合运算a b取两个计数的交集也就是每个字符取最小值构成的映射如果这个交集和a完全相等说明 magazine 的字符量覆盖得下 ransom_note 的字符量。这种一行写法放在面试里比 for 循环里套 if 的版本漂亮得多而且零第三方依赖。Python 刷题的优势就在这里dict、Counter、set、deque这些内置结构基本覆盖算法题 90% 的「容器」需求完全不需要为刷题额外装库。4. 按高频模块推进DP、二分与建图怎么刷才不翻车提示刷套题不是按仓库顺序一题题硬啃。你要按「模块」推进每类题一次性见十道套路才能内化。4.1 动态规划从爬楼梯到股票买卖的状态机动态规划是 LeetCode 中占比最大的一块也是最容易让新手产生黑匣子感的一块。很多人抄答案抄得很顺合上代码自己写就不知道dp[i]究竟代表什么。我的建议拿到一道 DP 题先别急着写状态转移先问自己三个问题——状态是几维的每一维的下标代表什么边界值给多少以最入门的爬楼梯为例dp[i]表示到第 i 阶有多少种爬法转移是dp[i] dp[i-1] dp[i-2]边界dp[0]1, dp[1]1。这句话说出来很简单但「为什么要设 dp[0]1」很多人答不上来——因为 0 阶到 0 阶算一种「不爬」的方案它让dp[2]的递推成立。搞懂这类边界比多刷五十道题更有用。动态规划里特别反直觉的一个类别是股票买卖系列。它要求你维护的不再是一维数组而是「第 i 天手里持有股票时的最大利润」这样的状态机def max_profit(prices): hold -prices[0] # 第 0 天买入手里持有股票 cash 0 # 第 0 天空仓利润为 0 for p in prices[1:]: new_hold max(hold, cash - p) # 继续持有或今天买入 new_cash max(cash, hold p) # 继续空仓或今天卖出 hold, cash new_hold, new_cash return cash逻辑说明hold代表当前时刻手里持有股票时的最大利润要么昨天就持有要么今天买入cash代表不持有股票时的最大利润要么昨天就空仓要么今天把股票卖出。注意更新时必须用上一轮的值所以先把新值算好再统一赋值而不是边算边覆盖——这是状态机会写错的最常见原因。理解了这个「持有/空仓」的二维状态买股票 I、II、III、含手续费、含冷冻期全部是一个模板换几个约束条件而已不需要重新想一套思路。4.2 二分查找073 爱吃香蕉的狒狒二分目标是速度不是堆二分查找看起来是最简单的算法但 LeetCode 上的二分是「在一个有逻辑的数组里找满足条件的极值」不是教科书里的array[mid] target。「爱吃香蕉的狒狒」原题 875 题中文区题号 073就是个典型案例N 堆香蕉警卫会在 H 小时后回来你要算最小速度 K使狒狒能在 H 小时内吃完所有堆。def min_eating_speed(piles, h): def can_finish(k): return sum((p k - 1) // k for p in piles) h # 向上取整求总耗时 lo, hi 1, max(piles) # 速度最小 1最大不超过最高那堆的根数 while lo hi: mid (lo hi) // 2 if can_finish(mid): hi mid # 当前速度够用试着压更低 else: lo mid 1 # 当前速度不够必须往快调 return lo参数说明(p k - 1) // k是「向上取整」的写法表示吃某一堆要花几个小时can_finish判定在总耗时不超过 H 时速度 K 是否可行。二分区间左端取 1最小每小时吃一堆右端取max(piles)比最高的一堆还快没有意义然后在「能不能完成」这个布尔条件上做标准二分。这题的坑在于判断条件「耗时 H」在解空间上是单调的——速度越大越容易完成所以可以二分。很多初学者试图对 piles 二分方向错了因为答案空间是速度不是香蕉堆本身。把这个「二分目标是什么」想清楚比记住模板重要得多。4.3 图与邻接表用 defaultdict 建图用 deque 做 BFS图的题在 Python 里最舒服的地方是建图。邻接矩阵用二维列表、邻接表用字典所谓「python构建邻接矩阵」基础就一行[[0] * n for _ in range(n)]。但刷题我更推荐邻接表 defaultdictfrom collections import defaultdict, deque def build_graph(edges): g defaultdict(list) for u, v in edges: g[u].append(v) g[v].append(u) # 无向图有向图删掉这行 return g def bfs(graph, start): seen {start} q deque([(start, 0)]) while q: node, dist q.popleft() # O(1) 出队列表 pop(0) 是 O(n) for nb in graph[node]: if nb not in seen: seen.add(nb) q.append((nb, dist 1))逻辑说明defaultdict(list)让「访问一个不存在的 key」自动创建空列表省去if u not in g: g[u] []这种三行初始化popleft()是 deque 的 O(1) 出队操作数据量上万时和列表pop(0)的差距非常明显。这个 BFS 模板里dist记录到起点的距离常见变体有「记录从起点走到当前节点的路径」「改成显式栈做 DFS」等。我把「建图 BFS 记录距离」作为一组固定模板存着每场周赛的图论签到题基本都能直接套。另一个值得养成的习惯是做图论题之前先确认题目是「有向还是无向」「有没有重边和自环」这决定了你是写一行g[v].append(u)还是删掉它也决定了seen要判几次重。5. 避坑Python 刷 LeetCode 最容易翻车的 5 个细节与排查方法5.1 可变默认参数函数调用自带「记忆」现象写题解时图省事定义了def f(x, lst[])第二次调用不传lst发现结果里混进了第一次的数据。原因Python 函数的默认参数只在定义时求值一次同一个列表对象被所有调用共享。这在 C/Java 背景的人看来完全反直觉因为那些语言的默认参数每次调用都会重新创建。解决默认参数一律写成None函数体内再if lst is None: lst []。这是 code review 里被提到最多的 Python 改法没有之一。5.2 循环里做字符串拼接数据量一大就超时现象把一组整数拼成结果字符串用s str(x)循环累计小数据没事数据一多就 TLE。原因字符串是不可变的每次都是创建新字符串并拷贝旧内容整体变成 O(n²) 的时间开销。解决收集结果到一个列表最后.join(lst)需要格式化输出时用 f-string 或format别硬拼。这也解释了为什么很多 Python 题解里到处是append到 list 再join——不是为了好看是为了活命。5.3 二维数组初始化[[0] * n] * m的整列变值事故现象想初始化一个 m 行 n 列的矩阵写了matrix [[0] * n] * m然后matrix[0][0] 1发现第一列所有行全变成 1。原因外层乘法复制的是同一个内层列表的引用m 行指向同一个对象。你不是建了 m 行你是建了 m 个「指向同一行的指针」。解决老老实实写[[0] * n for _ in range(m)]。列表推导式里的内层表达式每次迭代都会新建一个列表。这个坑出现频率极高几乎每个刷题新手都会踩一次值得当成条件反射来记要生成独立行的二维数组永远用推导式不要用乘法。5.4 递归深度同样的代码 C 能过Python 却过不了现象二叉树、回溯这类递归解法本地改几组小数据都正常一提交就 RecursionError 或者 Runtime Error。原因Python 默认递归深度限制是 1000LeetCode 的二叉树深度很容易突破另外 Python 递归本身就比迭代慢得多某些题用递归就是会 TLE。解决带递归深度风险的题先import sys; sys.setrecursionlimit(10000)如果还慢就改成显式栈的迭代写法。我在二叉树路径这类题上吃过不少亏背了递归版答案提交后超时最后改成栈模拟才过。排查顺序应该是先看是不是递归深度问题再看是不是状态重复计算没剪枝最后才怀疑是测评机太慢。5.5 负数取模Python 的%和 C 结果不一样现象一道数学题C 答案是 2Python 变成 -2。原因Python 的%按向负无穷取整结果与除数同号C/C/Java 按向零取整结果与被除数同号。两边在负数场景下结果不一致导致同一套思路在两个语言里输出不同。解决需要向零取整的余数时先算正余数再校正r a % n; if r ! 0 and ((a 0) ! (n 0)): r - n。或者改用math.fmod(a, n)它在负数场景下和 C 语言一致。这类「语言差异不是算法错误」的坑最耗时间排查时先确认思路没错再怀疑%与//的语义。6. 把题解做成自己的模板库对拍、重构与周赛里的验证最后聊怎么把整套题解真正变成你自己的。建议挑三道你刷过的题——一道二分、一道 BFS、一道 DP——用上面的模板各重构一遍然后对比提交记录里的耗时和内存把「时间复杂度和关键变量」用自己的话写进题解源码的 docstring 里。这个动作的意义在于几个月后面试复习时你只需要git log --oneline就能按 commit message 回看某一类题的结构而不是重新翻开几千个文件。验证环节我靠两件事。第一是随机样例对拍写一个暴力解和一个优化解随机生成小规模输入跑几千遍比对输出。这个习惯能揪出大量边界条件错误尤其是二分和 DP 的初始化问题。第二是拿「热门100题」里同类型的题做交叉验证比如每日温度做完顺手把「下一个更大元素 II」也做了看模板能不能直接迁移。周赛遇到新题我固定的流程是先套模板判断题型再写暴力确认边界最后换成优化写法提交。几场周赛跑下来你对「每类题该往哪个方向想」的判断速度会明显变快。我早先拿到标题里说的「全套解答」时是真把它当标准答案背过的结果一到周赛现场就现原形。血泪经验告诉我你能带走的只有本地测试骨架里那些被验证过的代码以及一次次翻车中积累的排查路径。模板是骨架测试是对照组周赛是体检——三者凑齐那套别人的题解才算真正消化成了你的东西。希望帮到你。本文还有配套的精品资源点击获取