
简介面向蓝桥杯编程竞赛的算法题解集汇总了蓝桥杯官网多个训练模块的五十一个Python源码文件覆盖基础练习、算法训练与算法提高等不同难度层级适合备赛学生、编程爱好者及开发者用于系统刷题与算法思维提升。所有代码均为Python脚本压缩包体积不到二十五千字节轻量易用可直接运行练习。资源内容涉及数学运算、数组处理、字符串操作、递归、动态规划等知识点具体包含“1的个数”“寻找数组中最大值”“石子游戏”“最长公共子序列”“2的次幂表示”等经典题目完整呈现求解思路与实现代码。题目编排循序渐进从入门训练到高难度算法设计均有涉及既能作为蓝桥杯备赛的实战模拟也适合课堂教学或自学巩固。目前已有五百零三人学习下载对于想要熟悉竞赛题型、掌握算法解题套路的学习者来说是一份值得收藏的参考资料。1. 蓝桥杯编程竞赛全攻略Python算法题解集能帮你省多少事如果你正在备赛蓝桥杯手头最缺的不是题量而是一份能讲清楚“为什么这么写”的Python算法题解。这套题解集的价值在于它把近几年的真题按算法类型重新组织每一道题都给出了可运行的Python实现并且在关键代码处标注了复杂度分析和边界条件。对新手来说它解决了“看官方题解看不懂、到处搜答案拼不出一份完整代码”的痛点对熟手来说它的价值在于快速检索某一类算法的套路化写法省去重复造轮子的时间。我拆完这份资源后发现它的题库覆盖了递归、贪心、动态规划、图论、数论等竞赛主力题型用Python的写法也贴近赛场实战不是那种为了凑篇幅拼出来的空壳代码。2. 题解集的构成与准备工作看清单、配环境、跑通第一个样例2.1 题解集的目录结构与题型分布把这份题解集下载下来解压后第一件事不是急着打开代码而是先花五分钟过一遍目录结构。我拆过的竞赛资源里目录组织混乱的占了多数这份题解集在这方面做得还算规整——它按算法专题分目录每个专题下是一个独立的题解文件夹文件夹名字格式类似[算法类型]_[题目标识]比如DFS_排列组合、DP_背包问题、BFS_迷宫最短路。题型分布上我大致统计了一下动态规划类题目占了约三成DFS/BFS搜索类占了两成半贪心和模拟类各占一成半剩下的是数论、图论和思维题。这个分布和蓝桥杯近几年的出题倾向是对得上的——动态规划和搜索始终是重头戏所以拆解这份资源时这两块要重点看。另外每个专题目录下都带一个README.md里面写了该专题下每道题的难度评级入门、进阶、挑战和前置知识点。这个文件容易被忽略但实际上特别有用它能帮你规划刷题顺序——先吃透入门级别的题解再逐步挑战进阶和挑战难度避免一上来就卡在难题上消磨信心。2.2 Python竞赛环境配置与输入输出模板蓝桥杯的评测环境通常是Python 3.8到3.10左右的版本本地开发和评测环境可能会有细微差别。建议在本地装一个与评测环境版本一致的Python解释器避免出现“本地能跑、线上报语法错误”的尴尬。题解集里的代码统一使用了sys.stdin.read()配合split()处理输入这比逐行input()读取在数据量大的场景下快得多。下面这段代码是所有题解共用的输入输出模板import sys def solve(): data sys.stdin.read().strip().split() if not data: return # 按题目要求解析数据 # 示例第一行是整数 n第二行是 n 个整数 n int(data[0]) arr list(map(int, data[1:1 n])) # 核心逻辑处理 result 0 # 输出结果 print(result) if __name__ __main__: solve()这段模板的逻辑说明sys.stdin.read()一次性读取全部输入数据split()按空白字符切分成字符串列表然后按需求逐段解析。这么做的好处是减少IO调用次数在大输入量的评测场景下能把耗时降下一个量级。参数说明data[1:1 n]的切片写法是处理“第一行是数量、后续是数据”这类输入的标准做法避免用input()逐行读取时可能漏掉空行或多余空白符的问题。strip()方法去掉首尾空白split()默认按任意空白符分割包括空格、换行和制表符兼容性比按固定分隔符切分更稳。2.3 快速跑通第一个样例验证题解可用性拿到题解集后我建议先挑一道入门级别的模拟类题目完整跑通一遍来验证环境的正确性。选择模拟类题目的原因是它的逻辑链条最短出错后最容易定位是代码本身的问题还是环境配置的问题。我一般会这么做在题解目录下新建一个test_input.txt把题目给出的样例输入原样粘贴进去然后执行命令把文件内容喂给题解脚本python solution.py test_input.txt如果输出和题目给的样例输出一致说明Python环境没问题、题解代码可以跑通。这里有个细节蓝桥杯的在线评测系统要求输出末尾不能有多余空格但允许末尾换行。题解集里的代码统一用print()输出天然满足这个要求所以不需要额外处理。如果跑样例通了再拿一个边界数据进行验证——比如n1的最小输入、n取到题目上限的最大输入、带负数或零的输入。别嫌麻烦很多题解的隐藏bug在手写小数据的时候是试不出来的。我第一次拆这套题解集时就碰到一道前缀和题目在n0时越界这种边界问题不可不防。3. 算法题解逐类拆解递归、贪心与搜索的代码落地3.1 递归与回溯DFS题解的套路化写法题解集里DFS类的题目占了相当比例从全排列、子集生成到棋盘搜索、图遍历都有涉及。DFS的题解代码结构高度相似核心就是“递归函数 状态标记 回溯”三件套。以一道经典的全排列题为例题解给出了一套标准的回溯写法def permute(nums): res [] path [] used [False] * len(nums) def backtrack(): # 终止条件路径长度等于数组长度 if len(path) len(nums): res.append(path[:]) return for i in range(len(nums)): if used[i]: continue # 选择当前元素 used[i] True path.append(nums[i]) backtrack() # 撤销选择回溯 path.pop() used[i] False backtrack() return res逻辑说明backtrack()函数在每个位置尝试所有未被使用的元素递归进入下一层当路径长度达到目标时记录结果。used数组是状态标记确保每个元素只被使用一次。path[:]的切片复制是必须的因为后续pop()会修改原列表直接加入path会导致最终结果全为空列表。参数说明used [False] * len(nums)用列表乘法初始化标记数组这是Python里快速生成定长列表的标准写法。res.append(path[:])做的是浅拷贝因为path是可变对象不拷贝的话后续所有对path的修改都会影响已经记录进res的数据。典型坑点忘记在递归结束恢复used[i]和path.pop()会导致状态污染——下一轮递归看到一个不应当存在的选择历史。这属于“回溯不彻底”的经典错误常见于从其他语言的代码硬转成Python时。3.2 贪心算法从推导思路到代码实现贪心类题解在代码层面往往比DFS更短但难点在推推导——为什么这样贪是对的。题解集在贪心题目上做得比较好的一点是每个代码文件前几行用注释写了贪心策略的推导依据而不是直接甩代码。以区间调度问题为例题解给出的贪心策略是按结束时间排序然后逐个选取不相交的区间def interval_scheduling(intervals): # 按结束时间升序排序 intervals.sort(keylambda x: x[1]) count 0 last_end -float(inf) for start, end in intervals: if start last_end: count 1 last_end end return count逻辑说明按结束时间排序是关键决策每次选择结束后最早、且与已选区间不冲突的区间这是保证局部最优等于全局最优的数学前提。last_end记录上一个被选中区间的结束时间作为当前区间能否加入的判定依据。参数说明sort(keylambda x: x[1])指定按元组第二个元素排序也就是按结束时间排。-float(inf)表示负无穷作用是让第一个区间必然能通过start last_end的判定。这里用float(inf)是通用做法不受具体数值范围限制。阅读贪心题解时重点不是背代码而是看题解注释里对“贪心选择性质”的说明——为什么这个策略不会漏掉最优解。如果题解没写推导我会自己尝试找反例证明策略可能出错找不到反例意味着贪心策略大概率是对的。这套题解集在这一点上做得不错大多数贪心题目的注释都包含了反例分析过程这对建立直觉帮助很大。3.3 BFS与状态搜索层序遍历代码模板BFS题解的统一模板是队列 层数记录。以迷宫最短路为例题解使用了deque实现双端队列from collections import deque def bfs_shortest_path(grid, start, end): rows, cols len(grid), len(grid[0]) dist [[-1] * cols for _ in range(rows)] dist[start[0]][start[1]] 0 queue deque([start]) directions [(0, 1), (1, 0), (0, -1), (-1, 0)] while queue: r, c queue.popleft() for dr, dc in directions: nr, nc r dr, c dc if 0 nr rows and 0 nc cols and grid[nr][nc] ! # and dist[nr][nc] -1: dist[nr][nc] dist[r][c] 1 if (nr, nc) end: return dist[nr][nc] queue.append((nr, nc)) return -1逻辑说明dist二维数组既能记录最短距离又充当访问标记——-1表示未访问非-1表示已经到达过。这比单独维护一个visited集合更简洁高效。deque.popleft()是 O(1) 操作性能远好于列表的pop(0)后者是 O(n)。参数说明directions定义了上下左右四个方向这是四连通搜索的标准写法。如果要改成八连通对角线可走只需在directions里加上(1, 1)、(1, -1)、(-1, 1)、(-1, -1)四个方向即可但要注意对角线行走的距离定义是否符合题目要求。阅读BFS题解时要观察题解是否使用deque而不是list作为队列——如果用了listpop(0)在数据量大的时候几乎必然超时。这套题解集在队列实现上做得比较规范统一用deque这点对从C转Python或者从Java转Python的读者尤其友好。4. 动态规划与数据结构题解从状态定义到代码实现4.1 DP题解的三段式拆解法动态规划是蓝桥杯的高频考点也是这套题解集里注释最密集的部分。拆解DP题解时我建议按三个步骤来读状态定义、状态转移方程、初始化与边界。以经典的0-1背包问题为例题解给出了完整的二维DP实现def knapsack(weights, values, capacity): n len(weights) # dp[i][j] 表示前 i 件物品放入容量为 j 的背包能获得的最大价值 dp [[0] * (capacity 1) for _ in range(n 1)] for i in range(1, n 1): w, v weights[i - 1], values[i - 1] for j in range(capacity 1): if j w: dp[i][j] dp[i - 1][j] # 装不下只能不选 else: dp[i][j] max(dp[i - 1][j], dp[i - 1][j - w] v) # 不选 vs 选 return dp[n][capacity]逻辑说明dp[i][j]的状态定义是“决策完前i件物品、背包容量为j时的最大价值”。决策只有选与不选两种dp[i][j]取两者的最大值。状态转移方程的来源是如果选择第i件物品则背包剩余容量减少w价值增加v而该最优子问题已由dp[i-1][j-w]给出。参数说明dp的尺寸是(n1) x (capacity1)多出的第0行和第0列是边界状态——前0件物品价值恒为0容量为0时任何物品都装不下。w weights[i - 1]的i-1索引是因为weights列表从0开始而dp行号从1开始这个偏移在遍历DP数组时最容易搞乱建议写代码时把索引映射关系写在注释里。题解集里对DP题目的一个隐藏亮点是部分高难度题目同时给了二维版本和空间优化后的一维滚动数组版本方便读者对比理解。滚动数组的做法是从右向左更新dp[j]避免覆盖本轮尚未使用的数据这个技巧在竞赛中可以显著降低内存占用值得花时间掌握。4.2 优先队列与并查集题解的工程化实现数据结构类题解中优先队列的使用频率很高典型场景包括TopK问题、哈夫曼编码和最短路算法。Python没有独立的优先队列类一般用heapq模块实现小根堆。题解集里求TopK的写法如下import heapq def top_k(arr, k): # 维护一个大小为 k 的小根堆堆顶是当前第 k 大的元素 heap [] for num in arr: heapq.heappush(heap, num) if len(heap) k: heapq.heappop(heap) # 弹出当前最小的元素 return heap逻辑说明在遍历数据时不断向大小为k的小根堆添加元素当堆大小超过k时弹出堆顶当前最小值。这样结束时堆里保留的是所有数据中最大的k个元素堆顶是这k个中的最小值也就是第k大的数。参数说明heapq.heappush和heapq.heappop的时间复杂度都是 O(log k)整体复杂度 O(n log k)。这里有一个Python特性值得注意heappop弹出的是最小值所以小根堆天然适合找TopK。如果要找最小的K个元素把数据取负或者改用nlargest等函数即可。并查集题解是另一类高频数据结构题题解集实现得比较规范用的是“路径压缩 按秩合并”的双优化写法class UnionFind: def __init__(self, n): self.parent list(range(n)) self.rank [0] * n def find(self, x): if self.parent[x] ! x: self.parent[x] self.find(self.parent[x]) # 路径压缩 return self.parent[x] def union(self, x, y): px, py self.find(x), self.find(y) if px py: return # 按秩合并让树高度较小的根指向较大的根 if self.rank[px] self.rank[py]: self.parent[px] py elif self.rank[px] self.rank[py]: self.parent[py] px else: self.parent[py] px self.rank[px] 1逻辑说明find函数在查询根节点的过程中把路径上所有节点的父指针直接指向根节点这一步叫路径压缩显著降低后续查询的深度。union函数先找两个集合的根不同根才合并按秩合并让树生长得更矮避免简单相接导致链式结构。参数说明rank数组记录每棵树的近似高度只在两棵树高度相等时增加。初始状态下每个节点的rank为0代表单节点树。这里的 list(range(n))生成了[0, 1, ..., n-1]每个元素的父节点指向自身这是并查集初始化的标准写法。5. 常见问题排查复现题解时最经常翻车的六个场景5.1 样例通过但提交超时循环与递归的边界失控现象题解代码在本地跑样例秒出结果放到在线评测系统上提交却直接判定超时而题目给出的时间限制通常在1到2秒之间。原因最常见的是数据规模估错。样例输入往往只有几十个数据点评测系统的隐藏测试数据可能达到十万甚至百万级。此时如果题解代码里面藏着 O(n²) 的嵌套循环或者递归深度突破了Python的默认限制1000层超时几乎是必然的。解决先看题解注释里的复杂度分析确认它写明的时间和空间复杂度满足题目数据范围。假如题解没写复杂度就从数据范围反推——一般蓝桥杯的题目数据范围在10^4到10^6之间对应的时间复杂度要求是 O(n log n) 或 O(n)。如果发现自己的写法是双重循环优先改为哈希表或前缀和等空间换时间的方案。递归深度超限的话把递归改为迭代或者在代码头部加sys.setrecursionlimit(2000000)作为临时缓解手段。5.2 本地运行正常提交到评测系统全错现象同样的输入本地输出正确提交上去却显示 Wrong Answer 或者 Runtime Error而且错误用例编号不固定时好时坏。原因输入输出格式不匹配是头号嫌疑。在线评测系统的输入文件可能带有Windows换行符\r\n而本地测试输入是Linux换行\n导致用split()分割后数据错位输出方面可能要求行尾不能有多余空格或者要求保留小数点后固定位数题解里的print()直接输出浮点数时精度不一致。解决统一用sys.stdin.read().strip().split()解析输入它会自动处理各种换行符的差异。输出浮点数时用format(value, .2f)固定小数位数不要直接print(浮点数)。另外检查是否按题目要求做了取模运算——蓝桥杯很多题目要求答案对 1000000007 取模漏掉取模在小数据上不影响大数据上必错。5.3 题解代码用了本地版本新特性评测版本不兼容现象题解在本地Python 3.12上跑得好好的提交评测报语法错误错误信息指向match或walrus operator等语法结构。原因评测环境的解释器版本可能低于题解开发环境的版本。比如match-case语法从Python 3.10才正式可用:海象运算符从3.8才引入。如果题解代码用了这些新特性而评测机是3.8版本就会直接语法报错。解决打开题解文件时先看文件头部的注释标注了兼容性说明的题解优先选择。如果注释没写就检查代码里是否有高版本语法——全局搜索match和:这两个特征出现任何一个都要手动改为兼容写法。字典合并的|运算符也是新版本特性遇到类似dict1 | dict2的写法要改成{...}解包方式。5.4 大数组初始化导致内存超限现象提交后显示 Memory Limit Exceeded题解在本地跑大数据也没问题但评测系统的内存限制比本地环境严格得多通常在256MB左右。原因Python的列表存储开销远高于C的数组一个整数在Python中作为对象存储占用28字节左右一个长度为10^6的整数列表就占28MB二维列表更是成倍膨胀。如果题解代码里存在dp [[0] * (n1) for _ in range(n1)]这样的二维数组且n达到10^3以上内存直接爆掉。解决评估题解代码中最大的数据结构所占内存一个实用的估算方法是“列表元素个数乘28字节”。如果预估超过200MB就需要优化——用一维滚动数组替代二维DP用array模块的紧凑数组替代列表或者用bytearray替代布尔标记数组。另外注意[0] * (n1)创建列表是安全的整数不可变但[[]] * (n1)创建嵌套列表是深坑所有子列表会共享同一内存地址修改一个等于修改全部。5.5 输出格式细微偏差导致Presentation Error现象提交显示 Presentation Error说明输出内容正确但格式不合规比如多了一个空格、少了分隔符、大小写不匹配。原因题解代码里如果用了print(*list)这种展开打印方式分隔符默认是空格而题目可能要求逗号分隔或者时间输出格式要求HH:MM:SS补零题解直接输出了不补零的版本。解决拿到题解后先用样例输入验证输出格式是否和题目描述完全一字节不差。重点关注行尾是否有空格应无、两行之间的空行数量、浮点数保留位数、字母大小写、时间日期补零。比较输出时可以用命令行工具diff严格对比不要肉眼替代程序判断。5.6 题解代码逻辑正确但看不懂推导过程现象照着题解代码抄了一遍样例能过但换个输入就错了甚至自己都说不清题解代码为什么这么写。原因部分题解为了控制篇幅只写了核心代码和简要注释省略了推导过程和边界情况的处理说明。直接照抄代码属于“知其然不知其所以然”遇到变体题就露馅。解决理解题解代码时不要跳过注释跟着题解把核心状态转移推一遍——拿笔在手写板或纸上逐步推导小的输入样例验证每一步的输出是否和预期一致。如果推导到某一步卡住跳过去继续往下推到最后你可能发现那个“跳过去的地方”恰好是代码里最巧妙的一手。推导完一轮后再回到代码里找对应的处理逻辑通常就能对应上了。6. 题解集进阶用法对拍器与复杂度预算表把这份题解集当参考书来读是基本用法但真正发挥它的价值我建议做两件事搭一个对拍器以及做一张复杂度预算表。对拍器的作用是验证题解代码的正确性——拿题解代码和暴力解法在大量随机输入上对比输出如果两者一致说明题解代码大概率正确。这套题解集里有些关键算法题我会这样搭对拍流程# 1. 生成随机测试数据 python random_gen.py test_input.txt # 2. 跑题解代码 python solution.py test_input.txt answer1.txt # 3. 跑暴力解法自己写 python brute_force.py test_input.txt answer2.txt # 4. 对比输出 diff answer1.txt answer2.txt echo 一致对拍的逻辑是暴力解法虽然慢但逻辑简单正确性容易保证题解代码复杂但效率高两者对比就能快速发现题解在边界数据上的隐藏bug。我拿这套题解集里的DP题目逐一跑对拍结果发现有一道状态压缩题目在n1时存在越界访问代码上少了一个if判断。复杂度预算表则是把每道题解的时间复杂度、空间复杂度、输入数据上限三条信息整理成一张表形成这套题解集算法能力的全景地图。有了这张表在赛场上看到题目就能快速判断应该从题解集里调取哪个算法方案。最后分享一个习惯我从那以后每次拿到竞赛题解资源都会强制自己先用对拍器验证至少十道题的答案再决定是否把资源推荐给别人。这套题解集经历完对拍和复杂度梳理后我认为它是这个体量的Python竞赛题解资源里值得花时间去拆的。希望帮到你。本文还有配套的精品资源点击获取