简介面向算法面试与LeetCode刷题人群的C题解合集以PDF形式整理了热题100中的经典题目及对应答案帮助读者在有限时间内掌握高频考点核心思路与代码实现。压缩包共包含1个PDF文件整体约640KB内容精炼、排版紧凑适合打印或离线阅读。目前已有1645人学习使用是准备校招、社招及算法竞赛的有效辅助资料。资源重点覆盖两数之和、两数相加、无重复字符的最长子串、寻找两个有序数组的中位数等高频题目每道题均提供完整C代码并标注时间/空间复杂度同时融入哈希表降低查找耗时、滑动窗口动态维护无重复区间、哑节点简化链表进位操作等实用技巧帮助读者理解常见解题套路。此外还配有解题思路说明与LeetCode平台使用建议读者可学习如何拆分复杂问题、检查边界条件并将方法迁移到同类型面试题中。1. leetcode热题100是什么给算法面试划重点的100道题如果你最近在准备算法面试「leetcode热题100题目加答案」这个搜索词应该不陌生。它背后指向刷题圈流传最广的那份百题名单100道题、覆盖主流考点、代码普遍不长但变体很多。很多人拿到这份名单的第一反应是找一份现成答案背下来但真正刷过的人都知道背答案的通常刷到一半就弃坑了靠它上岸的人是把「题目答案」重新组织成了自己的考点地图。这篇文章就照着这个目标讲热题100到底在考什么、答案写成什么样才能复用、最容易在哪里翻车以及最后怎么把刷过的题变成面试时能讲清楚的东西。适合两类人——时间紧、想用最少题目覆盖高频考点的求职者以及刷了不少题但总觉得「见过却不会讲」的开发者。2. 热题100的题型地图按数据结构拆开的高频考点分布拿到这份名单先别急着从第一题开刷先看分布。各平台维护的热题100版本不完全一样但结构高度稳定数组和哈希的题目大约占三成链表和二叉树合起来接近三成动态规划和回溯占两成上下剩下是二分查找、栈队列、图这类零散考点。这个分布不是随机凑出来的它对应面试官的真实出题惯性——越接近「手写核心逻辑」的题越常考。下面按模块拆开讲。2.1 数组与哈希基本盘也是其他一切题型的地基数组题占比最高因为它是代码量最小、最适合在面试对话里写完的题型。面试官能在十分钟里看到你写代码、讲思路、改边界整个过程都在一张白板上完成。这决定了数组类题目天然高频。而哈希表几乎是数组题的灵魂工具去重、计数、找唯一值、查补数都是它最擅长的事。我一般建议把数组和哈希类热题放在第一周按「先暴力、后优化」的顺序过。每道题先想最直接的解法哪怕复杂度很差也要能说出来然后再想怎么用哈希表降复杂度。以两数之和为例暴力是两重循环 O(n²)优化是哈希表 O(n)面试官真正想听的是你能从暴力开始推导出优化点。这类题里两数之和、三数之和、合并区间、移动零、最长连续序列都是热题名单里的常客。它们共同的特点是题干短、解法路径清晰、边界条件值得单独讨论。刷这一模块时给自己定个规矩——每道题手写出哈希表版本和双指针版本的区别什么时候该用哈希、什么时候双指针更省空间。这个判断力后面对滑动窗口和前缀和题型都有用。2.2 链表与二叉树迭代递归一起考基本功暴露最快链表和二叉树是热题100里另一个大块也是最容易「看答案觉得简单、自己写就出 bug」的部分。链表的坑在指针修改顺序反转链表时如果没有先用临时变量保存 next一改就丢链。二叉树的坑在递归出口和遍历顺序中序遍历写成先访问再递归输出就全错。面试官爱考这两种结构是因为它们能快速区分「背过模板」和「真的理解指针/递归」。链表题我建议拿到手先画图。比如反转链表先画出 1→2→3→4 的样子再标出每一步哪个指针指向哪里画完再写代码。二叉树题则先练迭代写法用栈模拟递归理解了系统栈的进出顺序再写递归就顺很多。这一模块的典型热题包括反转链表、环形链表、合并两个有序链表、二叉树中序遍历、二叉树最大深度、层序遍历。刷的时候注意一个原则每种遍历前序、中序、后序、层序至少手写一遍递归版和迭代版。别嫌重复很多二叉树题就是在基础遍历上套壳比如「验证二叉搜索树」本质上就是中序遍历后检查是否递增。2.3 动态规划与综合设计题拉分项藏在细节里动态规划和回溯是热题100里最劝退的部分。DP 的状态定义在初学者眼里很像玄学但它其实有套路先想最后一步做了什么再想倒数第二步怎么递推过来。爬楼梯是最简单的入门题状态转移就是 dp[i] dp[i-1] dp[i-2]最长递增子序列则要把转移条件从「固定依赖」改成「往前扫一遍找最大值」。回溯题的套路更固定选择、进入下一层递归、撤销选择。子集、组合总和、全排列都是同一个框架。刷这部分的时候别贪多每道题把状态转移方程写在代码前面写不出来就先看答案的推导过程再合上答案自己推一遍。设计题典型如 LRU 缓存出现在名单里是因为它同时考数据结构选型和工程封装。需求里读写都要 O(1)能想到哈希表 双向链表的组合说明对常用数据结构的性能特征有全局认识。这类题放到最后刷因为你需要前面链表、哈希的基础来理解为什么这样设计。综合题不多但拉分效果明显值得单独留时间。推荐顺序是死板的数组哈希 → 链表 → 二叉树 → 回溯与 DP → 设计与综合。前一个模块的工具是后一个模块的铺垫哈希思想贯穿始终递归理解又会反过来加深链表与树的熟练度。按这个顺序走比按题号从 1 到 100 顺刷合理得多。3. 把每道题变成一份可复用的答案两数之和到合并区间的完整模板别人整理的「题目加答案」质量再高也是别人的组织逻辑。你要做的是把每道题改写成自己的一份可复用答案。我的习惯是每道题固定五块内容一句话题干、思路先暴力后优化、复杂度、亲手重写的代码、边界与变体。这套结构对应面试真实流程——对方先让你说题意再问思路再问复杂度最后让你写代码并检查边界。3.1 答案模板一道题的标准解应该包含哪五块内容先说为什么暴力解法一定要写进思路里。面试很少直接问「最优解是什么」而是先问「你打算怎么做」如果你开口就是哈希表 O(n)对方会追问一句「还有更直接的办法吗」。能接住这句话的前提是你心里有暴力解法的复杂度并且知道它慢在哪。所以答案模板里暴力优化是一对缺一个都算没准备完整。复杂度这块要写推导不只是结论。比如哈希法为什么是 O(n) 时间因为一次遍历、每次查询摊还 O(1)空间 O(n) 是因为存了最多 n 个键值对。把推导写下来面试被追问时才不会只记得结论、说不出依据。代码必须是「重写版」而不是「粘贴版」。看答案时觉得自己懂了合上答案写出来卡住这是刷题最普遍的现象。重写的目的就是把这个差距暴露出来。你不需要把代码写得和参考答案一致但要能独立跑通、能讲清楚每行在干什么。3.2 完整示例一两数之和的暴力与哈希两种写法题目一句话给定整数数组 nums 和目标值 target返回相加等于 target 的两个下标每个输入恰好有一个答案。先写暴力版逻辑最直白def two_sum_brute(nums, target): n len(nums) for i in range(n): for j in range(i 1, n): if nums[i] nums[j] target: return [i, j] return []这段代码的逻辑很直接外层循环固定一个数内层循环从当前位置的下一个开始找找到配对就返回两个下标。复杂度是 O(n²)问题在于内层循环反复扫描已经检查过的组合。面试里先说出这个版本再指出「重复扫描是浪费」就自然过渡到哈希优化。再写哈希版本def two_sum(nums, target): seen {} for i, num in enumerate(nums): need target - num if need in seen: return [seen[need], i] seen[num] i return []这段代码的逻辑是一次遍历边访问边把数据记入哈希表。对当前数 num想找的是 target - num如果这个补数已经存在 seen 里说明之前某次的 num 和它互补直接返回两个下标。如果不存在就把当前数存进去等着后面的数来配对。存的时候 key 是数字本身value 是它的下标这样查找补数时可以同时拿到下标。参数方面要注意nums 是整数列表target 是整数。返回的列表是两个下标顺序按遍历到的先后排列题目保证有解所以正常情况下不会走到最后的 return []。边界情况是 nums 为空或只有一个元素此时肯定无解直接返回空列表。哈希版本的时空复杂度要能脱口而出时间 O(n)因为只遍历一次空间 O(n)因为最坏情况下把所有数字都存进了表里。3.3 完整示例二合并区间的排序与尾指针处理题目一句话给出若干区间 intervals把重叠的区间合并返回不重叠的区间列表。def merge(intervals): if not intervals: return [] intervals.sort(keylambda x: x[0]) merged [intervals[0]] for cur in intervals[1:]: prev merged[-1] if cur[0] prev[1]: prev[1] max(prev[1], cur[1]) else: merged.append(cur) return merged这段代码的逻辑是先把所有区间按左端点排序排序后重叠的区间一定相邻。然后维护一个结果列表 merged逐个处理剩余区间如果当前区间的左端点小于等于前一个区间的右端点说明两者重叠就把前一个区间的右端点更新为两者右端点的较大值否则当前区间与前面没有交集直接追加到结果。参数方面intervals 是形如 [[1,3],[2,6],[8,10]] 的二维列表每个子区间包含两个整数左端点小于右端点。代码里直接修改 prev[1] 是安全的因为 prev 是 merged 中最后一个元素的引用原地修改会同步到结果列表。边界情况有两个空列表直接返回空只有一个区间时循环不执行原样返回。复杂度是 O(n log n) 时间排序主导O(n) 空间用于存储结果如果要求原地处理也可以直接在输入列表上操作。这个题的变体是「插入区间」区别在于插入时先要定位插入点再复用同样的合并逻辑。提示面试官问复杂度时需要把时间和空间都说清楚并附带一句推导。只报结论不报依据是最容易被追问卡住的表现。4. 建立自己的热题100答案库归档方式与三轮复习节奏单题答案是战术100题怎么归档是战略。很多人的做法是收藏一份别人整理的 PDF 或博客看的时候觉得都有了真到面试前想复习却不知道从哪翻起。我一般把热题100组织成一份 Markdown 仓库一个文件一个模块一张卡片一道题。这样做的原因是纯文本可搜索、可维护面试前能按模块快速扫一遍还能随时往卡片里补充变体。4.1 用答案卡给每道题归档一张卡片五块内容每一道题对应一张卡片格式固定## 题目两数之和 ### 一句话题干 给定整数数组 nums 和目标值 target返回两个下标使对应元素相加等于 target。 ### 思路 - 暴力两重循环O(n^2)。问题重复扫描已检查过的组合。 - 优化哈希表存已见过的值遍历时查补数 target - numO(n)。 ### 复杂度 - 时间O(n)一次遍历哈希查询摊还 O(1)。 - 空间O(n)seen 表最多存 n 个键值对。 ### 代码 这里贴你自己重写过的、能直接运行的版本 ### 边界与变体 - 边界空数组 / 单元素 / target 在两端。 - 变体数组升序时可用双指针空间降到 O(1)三数之和在外部加一层循环。写答案卡时最重要的原则是代码一定是自己重写过的而不是复制来的。复制来的代码不会在脑子里留下痕迹复习时你会误以为自己会了但手放到键盘上就露馅。我见过很多人的笔记里代码漂亮整齐但问几句就答不上来问题都出在只收藏没重写。这一章还有个容易被忽略的细节题意不要抄原文用自己的话写一遍。这个习惯能训练「复述问题」的能力而它是面试第一关。4.2 三轮复习节奏模块轮、变体轮、错题轮轮次目标做法时间参考第一轮覆盖全部100题按第2章的模块顺序每天一个模块逐题建答案卡三到四周第二轮打通题型迁移把相同题型的题目放一起连做只讲思路不重写代码一到两周第三轮消灭薄弱点只看错题本每道错题直接在白板写完整答案持续到面试前第一轮最容易犯的错是追求数量、一天刷十五题但每道都没写透。我一般建议每天三到五道就够但每道都要走完「独立写代码→核对→补变体」这个完整流程。第二轮的关键是只讲思路这样可以快速过题把时间花在「看到题就能说出解法」的熟练度上。第三轮其实没有截止点从第二周开始每周抽两天把错题本过一遍直到每道错题都能不看笔记写出来。三轮之间不要穿插着来。第一轮没走稳就进第二轮会导致第二轮大量题目想不起思路又得回头翻卡片效率反而更低。4.3 变体题记录解决「原题会、变形废」的关键面试翻车最典型的场景不是原题写不出来而是原题刷过、稍微改一下就懵。热题100里大量题目互为变体两数之和变三数之和爬楼梯变最小花费爬楼梯二叉树中序遍历变验证二叉搜索树。如果每道题是一张孤立的卡片变体之间是连不起来的。我的做法是把变体挂在原题卡片的「边界与变体」字段下。遇到一道新题先判断它的原型是哪张卡然后回到那张卡补充一条变体记录。比如两数之和的卡上我记着三条数组升序时用左右指针、输出所有组合而不是一组、外层套循环变三数之和。面试时只要聊到两数之和这三条就是现成的延伸话题不需要临时想。变体记录的核心不是把新题写进新卡而是让旧卡长出分支。这个操作会迫使你关注题目之间的联系而不是孤立地记答案。刷到后面你会发现热题100真正在训练的就是识别「这道题其实是在考什么」的能力——哈希去重、双指针收缩、递归遍历、状态转移来回就这几板斧。5. 热题100避坑指南5个刷题翻车现场与应对方法这一章写的是血泪经验。下面这五个场景多数来自复盘别人的刷题记录有几条我自己也踩过。每条都按「现象→原因→解决」来讲照着改能避开大部分无效努力。5.1 背答案不背复杂度面试被追问当场露馅现象原题能写出来代码也没错但面试官追问「为什么这个解法是 O(n)」「空间还能不能省」时突然接不上话只能重复答案原文里的结论。原因只记了代码没记复杂度推导。答案里写「时间 O(n)」是结论不是理由不理解哈希查询为什么摊还 O(1)就无法应对任何变式提问。解决每张答案卡的复杂度字段都必须写一句推导。哈希法是「一次遍历 每次查询摊还常数」排序法是「排序 O(n log n) 主导」暴力法是「两层循环各自遍历 n」。会推导的人即使忘了结论也能现场算出来。5.2 按题号从 1 刷到 100刷到一半弃坑现象刷到第 30 题觉得吃力刷到第 50 题发现前面的全忘了最后名单没刷完信心也没了。原因题号是题目在那个平台题库里的原始编号与难度、题型都没有关系。按题号刷意味着难度忽高忽低同一题型不能集中训练记忆自然留不住。解决先把热题100按第2章的模块重排数组哈希、链表、二叉树、回溯 DP、设计题各成一节。一个模块一个模块吃透模块内再按「经典题→变体题」排序。这时候你会发现学习曲线变成了阶梯式上升而不是过山车。5.3 只看不写答案永远不属于你现象看参考答案觉得每一步都合理甚至能预感下一行代码要写什么但合上答案自己写第一行就卡住。原因阅读理解和代码生成是两套能力。能看懂别人写的代码不代表你的手能组织出同样的逻辑。看十遍答案不如动手写一遍暴露问题。解决每道题至少独立重写三遍。第一遍默写卡住的地方就是你的知识缺口第二遍不看任何资料写完后对照答案检查边界和代码风格第三遍合上所有资料对着白板写下完整解法并口头讲一遍思路。三遍之后这道题才真正开始属于你。5.4 只留最优解不会暴力解现象所有答案卡里都只有一个解法而且是最优方案。面试官说「先说说你第一反应怎么做」你只能想起最优解又觉得直接背最优解有点突兀。原因参考答案通常把最优解放在前面暴力解被跳过了。但面试交流的节奏是「从朴素想法开始逐步优化」而不是直接跳到终点。解决每张卡片的思路字段强制写两个版本暴力和优化。暴力解不用写代码但要能说清它的做法和复杂度以及「慢在哪里」。这样面试时你可以从容地走完整条推导路径而优化解变成对话的自然结论不是背出来的结果。5.5 不复盘边界条件换一组输入就翻车现象自己在本地测试样例全过面试官追加一个输入——空数组、只有单个元素、所有数字都一样——代码立刻报错或者输出错误。原因平时刷题只跑题目给的示例没有形成固定检查边界的习惯。边界是算法题最常见的隐性扣分点尤其链表题和区间题。解决每道题写完代码后固定跑四组输入空输入、单元素、全相同元素、最大规模。这四组不一定每题都适用但用来建立肌肉记忆很有效。跑出问题就补进答案卡的边界字段里下次复习这道题时边界本身就是一道小题。6. 从会做到能面试把热题100讲出来的练习方法刷题和面试是两件事。刷题时你面对的是编辑器面试时你面对的是人两者对输出的要求完全不同。热题100的价值不在于背下 100 份答案而在于这些典型题覆盖了面试可能切入的绝大多数角度。怎么把这些积累在面试现场变成分数需要一套固定的讲题方法。6.1 讲题三段式复述、思路、手跑我习惯把一道题的面试讲述压缩成三段第一段用 30 秒用自己的话复述题意并随手举一个最小例子。这个环节的意义是确认你和面试官对题目的理解完全一致同时给自己留出组织思路的时间。第二段从暴力解讲起一句话说清做法和复杂度再讲优化解法重点说清楚优化点的来源——比如「暴力每次都要重新找补数用哈希表把历史查询变成 O(1)」。第三段写代码前先说出要处理的边界写完后用手里的例子在草稿上走一遍逐行对应。这套三段式的好处是每一步都有明确产出复述让面试官知道你理解题意思路展示推导能力手跑展示对代码的实际掌控。三个环节里最容易被忽视的是最后的「走一遍」但很多边界 bug 就是在这一步被自己发现的。6.2 在草稿上推进样例把「看懂了」变成「讲得清」具体操作以两数之和的哈希版本为例。拿到样例 nums [2, 7, 11, 15]、target 9在草稿上画一个空表然后照着代码走i0num2need7表里空把 2 存进去i1num7need2表里有 2返回下标 [0, 1]。整个过程不超过一分钟但你能指着表说清楚每一步的状态变化。练习的时候不要只在脑子里走真的拿笔在纸上画。这能模拟面试白板环境也能让手指记住代码的推进节奏。某次面试我把合并区间的代码写对了却在讲复杂度时顺口说成 O(n)面试官追问「排序呢」当场愣住。那之后我养成了一个习惯任何一道题合上编辑器之前先对着空白的屏幕把思路讲完复杂度用一句话推导给它听。热题100只是入口讲得出来才算真会。希望帮到你。本文还有配套的精品资源点击获取