简介:《算法300题题目大全PDF》是一份源自芬兰 CSES 平台的算法练习题合集,面向ACM竞赛选手及备战技术面试的开发者。该PDF将CSES网站上的300道经典题目完整整理,涵盖数据结构、排序、搜索、图论、动态规划、贪心策略等核心算法领域,每道题均包含清晰的问题描述、输入输出格式及样例测试用例。资源共1个PDF文件,压缩包约31.43MB,便于离线刷题与复习。目前已有257人学习使用。由于CSES在国内可能访问受限,这份PDF解决了无法在线浏览的痛点;同时配合VJudge虚拟评测网址,可在线提交代码获得实时反馈,GitHub上的cses-solutions题解仓库也可供对照学习。题目按难度递进,适合由浅入深地练习。对准备ACM竞赛或面试算法题的学习者而言,这是一份系统、实用的题库资料,能有效帮助提升算法设计与实现能力。
1. 算法 300 题:一份能当搭子的题目大全,比想象中的有用
先别急着找下载链接。算法 300 题这个说法,在刷题圈里流传很久了,它不是一个官方标准题库,而是大家约定俗成的一个提法:把面试里高频的题型压缩成 300 道左右,按专题排布,覆盖面足够,量也压得住。对准备技术面试、考研复试、竞赛入门的人来说,一份整理得当的题目大全 PDF,核心价值是这三点:离线可查、可以标记进度、每道题附带思路提示,让你在地铁上、等编译的时候掏出手机或电脑翻几道题,而不是打开网站被瀑布流信息带走注意力。
但这里有个现实问题:市面上流传的所谓"300 题大全 PDF",大多存在题目残缺、无答案、排版混乱、直接扫描件无法检索这些毛病,你根本没法在上面做标记。这篇文章想讲清楚的是另一个方向:如何自己动手把一套规范的算法 300 题资料整理成一份可检索、可标注、带难度分级的 PDF,并且用它规划一整轮刷题计划。这件事适合谁?适合那些已经不满足于"刷题数量"、开始追求"题目质量 + 计划可执行"的人。
我不会假装自己手里有什么珍藏版资源,只是想借着"题目大全"这个需求,把选资料的标准、整理方法、刷题节奏和常见翻车点拆给你看。这是很多人在刷题三个月后才慢慢悟出来的东西,你不需要走同样的弯路。想要这份资料的落地价值,自己动手整理一次,比到处求资源要靠谱得多。
2. 拆解 300 题的内部结构:先搞清这份大全里该有什么
2.1 为什么是 300 而不是 500 或 1000
算法的题型广度和面试覆盖面之间存在一个平衡点。5000 题级别的题库适合竞赛选手长期浸泡,但对大多数准备求职或考研复试的人来说,时间和注意力都是限量的。300 题这个量级,按每天 3 道新题 + 5 道复习题的节奏,大约 6 到 8 周能过完第一轮,这正好卡住一般人的专注周期。
我见过太多人一上来就下载了某个 1000 题合集,刷了两周还在数组和字符串里打转,然后放弃了。反而 300 题这个规模,能逼着人规划、取舍,并且在第一轮结束时产生实实在在的"过完一遍"的成就感。从题型覆盖上看,300 题也足够把主流面试考点铺满:数组、字符串、链表、栈与队列、哈希表、二叉树、图、动态规划、贪心、回溯、排序与二分,每个专题 20 到 40 道题,密度刚好。
2.2 一份合格的题目大全 PDF,应有哪四个组成部分
根据我整理和使用的经验,合格的题目 PDF 不能只是题干的堆叠,至少需要四个板块:题目标题与编号、难度标签、知识点归属、以及一道题的完整信息链(题干 + 约束条件 + 示例输入输出)。缺少任何一个,刷到后期都会难受。
举例说明,动态规划专题里经常遇到这类题:一个经典二维 DP 路径计数问题,题干很短,但边界条件非常多。如果 PDF 里没有标注"状态转移方程是否需要特殊处理第一行和第一列"这类提示,你在复习时就得重新推导一遍。对 PDF 整理来说,我的经验是每道题给三行字段:难度标注(入门 / 进阶 / 挑战)、知识点(对应到数据结构或算法范式)、一句话思路提示。这个提示不要写完整解法,只写"从哪个角度切入",用来在复习时做自测。
2.3 一个可直接用的 300 题专题分布清单
下表是我个人比较推荐的一版专题分配方案,覆盖 11 个主要方向,总共 300 题。不需要照搬,但可以作为自己整理时的骨架参考。
| 专题 | 题数 | 难度分布建议 | 备注 |
|---|---|---|---|
| 数组与矩阵 | 30 | 入门 15 / 进阶 10 / 挑战 5 | 双指针、滑动窗口高频 |
| 字符串 | 20 | 入门 10 / 进阶 8 / 挑战 2 | 注意回文、子串类 |
| 链表 | 20 | 入门 10 / 进阶 8 / 挑战 2 | 环形链表是常客 |
| 栈与队列 | 20 | 入门 10 / 进阶 8 / 挑战 2 | 单调栈值得重点做 |
| 哈希表 | 20 | 入门 12 / 进阶 6 / 挑战 2 | 两数之和变体非常多 |
| 二叉树与递归 | 40 | 入门 20 / 进阶 15 / 挑战 5 | 遍历、最近公共祖先 |
| 图与搜索 | 30 | 入门 10 / 进阶 15 / 挑战 5 | BFS / DFS / 拓扑排序 |
| 动态规划 | 50 | 入门 20 / 进阶 20 / 挑战 10 | 背包、序列、区间三类核心 |
| 贪心算法 | 20 | 入门 10 / 进阶 8 / 挑战 2 | 区间贪心是重点 |
| 回溯算法 | 20 | 入门 8 / 进阶 8 / 挑战 4 | 排列、组合、子集 |
| 排序与二分 | 30 | 入门 15 / 进阶 10 / 挑战 5 | 二分边界是易错点 |
| 总计 | 300 | - | - |
注意这个表里,动态规划和二叉树占了三分之一,这不是偶然,这两个大方向确实是面试中出现频率最高的。整理时如果某类题目凑不齐数量,宁可削减数量也不要塞一些冷门偏题拉低整体质量。
3. 动手整理一份可用的题目大全 PDF:从数据清洗到生成
3.1 数据从哪来:先建题目标题清单,再补充题面
不编造资源,但可以告诉你我在整理时的数据来源策略。常见做法是:从若干个公开的算法题库里,按专题人工挑选高频题。挑选标准不复杂:题目是否出现在多家题库的"高频"或"热门"列表里,或者是否符合某一类经典题型(例如 LIS、LCS、背包九讲里的基础变种)。
把题目标题和题目描述统一成一个 Markdown 文件,格式可以像下面这样:
## T001 | 两数之和 难度: 入门 知识点: 哈希表 题干: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。 约束: 2 <= nums.length <= 10^4;-10^9 <= nums[i] <= 10^9;只会存在一个有效答案。 示例 输入: nums = [2,7,11,15], target = 9 输出: [0,1] 思路提示: 遍历数组时,用哈希表记录"当前值期望匹配的那个数"是否已出现过。逻辑说明:我用 T 加三位数字作为每道题的唯一编号,方便将来做索引和交叉引用。题干和约束必须分开写,因为实际刷题时约束条件决定了算法能否暴力解,很多时候你扫题干后第一眼要看的就是数组长度上限。思路提示统一放在最后一行,方便在打印或 PDF 渲染时折叠查看。
参数说明:难度字段只用三种取值,避免"中等偏上"这类主观描述带来的分类混乱。知识点字段要精确到具体的数据结构或算法范式名称,不写"综合题"这种模糊标签。
3.2 用脚本把 Markdown 自动渲染为带锚点的 PDF
人工把 300 道题复制进 Word 排版,那是自己折磨自己。我一般是用 Pandoc 配合一个简单的 CSS 文件渲染 PDF。为了避免每次重新渲染时重复劳动,可以先写一个简单的 Python 脚本,把 Markdown 按专题切分成多个临时文件,再逐个转 PDF 后合并。
import subprocess import pathlib import re topics = ["array", "string", "linkedlist", "stack_queue", "hash", "tree", "graph", "dp", "greedy", "backtrack", "binary"] base_dir = pathlib.Path("algorithm_300") def split_by_topic(md_content: str) -> dict: # 按## 专题名 切分内容 例如 "## 专题: 动态规划" topic_blocks = {} current_topic = None current_lines = [] for line in md_content.splitlines(): if line.startswith("## 专题:"): if current_topic: topic_blocks[current_topic] = "\n".join(current_lines) current_topic = line.split(":")[1].strip() current_lines = [] else: current_lines.append(line) if current_topic: topic_blocks[current_topic] = "\n".join(current_lines) return topic_blocks def render_pdf(md_path: pathlib.Path, css_path: pathlib.Path, out_dir: pathlib.Path): out_file = out_dir / (md_path.stem + ".pdf") subprocess.run([ "pandoc", str(md_path), "-o", str(out_file), "--css", str(css_path), "--pdf-engine=weasyprint", "-V", "geometry:margin=2cm", ], check=True) def main(): full_md = base_dir / "algorithm_300.md" content = full_md.read_text(encoding="utf-8") blocks = split_by_topic(content) out_dir = base_dir / "pdf_parts" out_dir.mkdir(exist_ok=True) for topic, text in blocks.items(): tmp_md = out_dir / f"{topic}.md" tmp_md.write_text(text, encoding="utf-8") render_pdf(tmp_md, base_dir / "style.css", out_dir) print("分专题 PDF 已完成") if __name__ == "__main__": main()逻辑说明:这个脚本的核心价值不是转换本身,而是把 300 题的维护成本降下来。新增一道题只需要改总 Markdown 文件,不用碰样式和排版。按专题切分后的 PDF 也有实用意义:刷动态规划这一周,只用把 dp.pdf 放进平板或手机里,文件小、加载快。
参数说明:--pdf-engine=weasyprint是 CSS 支持最好的引擎,常规代码块样式、字体设置都能正确渲染。如果你的环境里没有 weasyprint,也可以用--pdf-engine=wkhtmltopdf替代,但后者对中文的默认字体支持稍差。geometry:margin=2cm控制页面边距,打印出来做手写笔记时 2 厘米的页边距比较适合。
3.3 PDF 之外的配套:一个可勾选的刷题进度表
300 道题如果没有进度管理,刷到最后自己都不记得哪些做过了。我会在同一个目录下放一个简单的进度表,用 Markdown 的复选框语法来标记状态,这样可以像记账一样每天更新。配合脚本将进度表单独渲染成一个一页纸的 PDF,放在手机里每周查看。
| T001 两数之和 | 哈希表 | 入门 | 状态 | 错误次数 | 复习标记 |
|---|---|---|---|---|---|
| T002 有效的括号 | 栈与队列 | 入门 | 已完成 | 1 | 2 周后 |
| T003 合并两个有序数组 | 数组 | 入门 | 进行中 | 0 | - |
逻辑说明:这个 Excel 或者 Markdown 表格的价值在于"错误次数"列,它直接暴露你的薄弱点。如果一道题错了三次以上,说明不是粗心,而是这类题目的套路没有真正内化,需要回到知识点重新看。
整理完成后,整个目录结构类似这样:algorithm_300/下有一个总 Markdown 源文件、一个 CSS 样式文件、一个进度表文件、以及按专题切分生成的 PDF 文件。这就是一份完全属于自己、可持续维护的"题目大全 PDF"。
4. 刷题阶段的常见坑与排查:见了这些问题别慌
4.1 题面过长导致复习意愿下降
现象:一份 PDF 里来几道题干特别长的题,页面要翻两到三屏,看起来就心烦,复习时直接跳过。
原因:这类题往往是从英文题目机械翻译,句子冗长,各种背景故事铺垫占了 60% 的篇幅,真正的数学结构和算法要求只有最后一两句话。
解决:在整理阶段就做"题干压缩"。把背景故事全部删掉,只保留输入输出的形式化描述。我的经验是:任何题目,都能在三行内说清楚输入是什么、输出是什么、特殊条件是什么。题面如果压不到三行,说明你自己还没理解这道题在问什么,这种状态刷题效率极低。
4.2 答案和题目分离,来回翻页打断思路
现象:很多资源喜欢把题目放前半部分、答案解析放后半部分,题目编号也不一致,做一道题要来回跳页码。
原因:这种排版方式是为了打印和排版方便,没有考虑阅读体验。
解决:自己整理的 PDF 里,建议把伪代码或解法要点放在题目正下方,与题干之间用一条分割线隔开,但在进度管理上标注"看答案前先尝试 20 分钟"的纪律。这里的矛盾点是:物理上放在一起,客观上没法避免瞟两眼。所以要用自制力配合约定:答案区域用浅灰色背景或斜体字提示区分,从视觉上形成"没做完不看下方"的心理暗示。
4.3 专题顺序设计不合理导致刚开刷就卡住
现象:有人一上来先刷动态规划 50 题,刷了 10 天后怀疑人生,觉得自己不适合算法。
原因:动态规划是典型的"需要前面多个专题做铺垫"的内容,没有数组遍历、递归思想的基础,一上来就接触状态转移方程,认知负担过大。
解决:按前置依赖排序,我推荐的刷题顺序是:数组与字符串 → 哈希表 → 栈与队列 → 链表 → 二叉树 → 排序与二分 → 回溯 → 贪心 → 动态规划 → 图与搜索。把最难的动态规划和图放到后半程,先建立基础题的肌肉记忆。
4.4 每题都要完整 AC 才罢手导致节奏崩溃
现象:有些人刷题时卡在一道中等难度题上四小时不放手,非要当场通过全部测试用例,结果一天只做了两道题,焦虑爆表。
原因:刷题练习的目标不是"每道题都独立 AC"(那是比赛状态),而是覆盖题型。在一轮刷题计划里,看思路、捋清框架、按答案的伪代码自己实现,同样能达到学习效果。
解决:给自己定一个 45 分钟上限。超过 45 分钟没有完整思路,就翻开答案看解法要点,然后合上答案自己写代码实现。注意是看"解法要点",不是照着抄代码。这一条能拯救大多数人的刷题进度。
4.5 PDF 渲染后中文乱码或代码块不换行
现象:生成的 PDF 里,中文标题和题干能正常显示,但代码块里的代码超出页面边界,直接把单词截断。
原因:WeasyPrint 默认对代码块使用等宽字体,某些 CSS 样式对折行处理不好。
解决:在 CSS 里给代码块加上white-space: pre-wrap; word-break: break-all;两个属性,强制超长行换行。同时把代码块的默认字体设置为monospace,避免个别系统对等宽字体解析异常。
5. 用这份 PDF 规划完整的刷题周期:从第一轮到错题回炉
5.1 三轮刷题法的具体时间分配
拿到整理好的 300 题 PDF,怎么按周推进性价比最高?业内说得最可靠的方案是三轮法。第一轮是"过题型":按专题顺序,每天 3 道新题,每道题控制在 45 分钟内,不追求独立 AC,核心目的是让大脑对所有题型有一个全局印象。这轮通常需要 6 到 7 周。
第二轮是"刷薄弱":一轮结束后,翻进度表里"错误次数 >= 2"的题,重新做一遍,时间减半到 20 分钟一道,主要是练手感。第三轮是"模拟题":从每个专题里随机抽 1 到 2 道题组合成模拟套题,两天一次,训练切换题型的敏捷度。这个阶段可以在这个 PDF 里按编号顺序打乱做,而不是按专题做,模拟面试中随机出题的场景。
期间有一个细节容易忽略:PDF 里的难度标签是为了初始选题时做平衡的,但经过一轮之后,你对难度的体感会发生变化。建议自己在进度表里维护一列"个人难度",用来替代资料的原始标注。这个个人难度在第二轮和第三轮的题目筛选中才真正有用,因为资料标注的"挑战"可能对你来说被你完全掌握了,而某些"入门"题由于思维惯性反而总是出错。
5.2 每日固定节奏:新题与旧题的比例
每日做题数量不是越多越好,更重要的是新题和旧题的比例。我常用的一组参数是每天 3 道新题 + 5 道旧题。旧题的来源是三天前做过的题,这个间隔能有效激活记忆曲线中的重建过程。格式上可以在 PDF 目录里用不同颜色的高亮标注日期,把某月某日的新题和旧题编号单列一页"当日任务单"打印出来,做完一道划掉一道,这个动作有很强的执行价值。
这 5 道旧题的选取规则是这样的:如果错误次数最多,优先;如果难度标签与个人能力匹配,其次;如果三道新题中已经覆盖了相同知识点,则可以跳过。优先级靠后的题不刷也不会造成遗漏,因为第二轮会重新覆盖。每日任务单的长这样:
| 任务类型 | 题目编号 | 预计时间 | 实际用时 | 是否卡壳 |
|---|---|---|---|---|
| 新题 | T045 | 35 min | 30 min | 卡在边界 |
| 新题 | T102 | 40 min | 45 min | 无想法 |
| 旧题 | T017 | 15 min | 12 min | 通过 |
5.3 错题信号捕捉与优先级排序
错题不是平均用力重新刷,而是按信号排序。三个典型的错题信号:一是"无思路"型,看见题面一片空白,说明这类题的套路你还没建立;二是"思路偏"型,有点想法但走不通,说明你对某种经典解法的适用条件理解不到位;三是"边界崩"型,解题思路对但漏了空数组、最大数这些边界条件。
三类里面,优先级从高到低是"无思路" > "边界崩" > "思路偏"。无思路说明知识点有漏洞,需要回到知识点板块重新看;边界崩说明代码习惯需要端正,多练边界用例;思路偏说明你往往是想复杂了,这类题要靠反复做来形成条件反射。我在第二轮刷题时,会把错误类型直接记在 PDF 题目旁边,形成一道题的个人反馈闭环。
6. 把 PDF 用活:给题目维护"一句话思路索引"的进阶技巧
这里分享一个我实际用了很久的方法,适合那些已经过完第一轮、想在第二轮显著提速的人:在 PDF 的每一页题目下方,加一行空白备注,每次刷完这题后,用不超过 20 个字写下你的"个人解题指纹"。它不是标准答案,而是你自己对这道题的记忆钩子。
举例来说,某道关于区间合并的题,你写的可能是"排序 + 判断相邻区间交叠,维护当前右端点"。某道关于二叉树最近公共祖先的题,你写的可能是"分治,左右子树各找一次,都找到则根为答案"。这些话外人看了觉得粗糙,但你自己回头看时会瞬间复原整个思考过程,比读完整解析快得多。
为什么要用这种"一句话思路索引"而不是直接把完整题解放上去?因为第二轮刷题时,你的目标不是重新学习解法,而是测试自己能否通过这个钩子顺完整个推理链。如果一句话索引能让你在两分钟内想起全貌,说明这题已经焊死在你脑子里了。如果想了五分钟还是想不起任何线索,那这题需要复杂标记,进入第三轮的模拟题清单。
这个索引的编辑过程可以直接在 Markdown 源文件里维护,重新渲染 PDF 后打印。建议每次渲染后单独导出一份只含题目编号和索引字段的速查页,放在手机里通勤时快速翻看,相当于把 300 题压缩成了几页关键词表。
我的个人习惯是每周日花 15 分钟更新索引,同时把本周错误次数最多的题型做一个标记,为下一周的复习量化一个重点。这套流程看起来简单,执行起来却很有效——它最大的价值不是让 PDF 更漂亮,而是逼着你把每题都过了一遍输出。记住,一份题目大全的真正价值不是"拥有",而是你在上面留下的思考痕迹。资源只是起点,你在这份 PDF 上的标注、批注和整理才让它变成独属于你的题库。希望这套整理与刷题的方法能帮到你,少走一些我曾经走过的弯路。
本文还有配套的精品资源,点击获取