尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

力扣刷题第二阶段:从跟风到刻意练习的完整拆解

发布时间:2026/9/19 2:58:24

资讯中心
01
ARTICLE

力扣刷题第二阶段:从跟风到刻意练习的完整拆解

力扣刷题第二阶段:从跟风到刻意练习的完整拆解
入行第三年刷过的题加起来也有三四百道了。LeetCode力扣对我而言早就不只是面试前的临时抱佛脚工具更像是一面照妖镜哪里基础不牢、哪里思维偷懒、哪里眼高手低一刷便知。这次整理的是我力扣刷题记录的第二阶段从“跟风刷题”转向“刻意练习”的过程踩了不少坑也摸索出一套还算高效的路子。今天把它们全量拆解出来希望能给正在刷题的朋友一点参考——尤其是那些刷了几十道题就卡在“简单题全会、中等题全废”阶段的同学这篇内容应该正好对路。这个阶段我刷了大约80道题以力扣热题100为主线穿插了部分高频企业题。核心思路不再是把题做出来而是把每一道题吃透优化时间复杂度、对比不同解法、总结题型套路。过程中最大的体会是刷题数量固然重要但真正拉开差距的是刷完之后有没有做题型归类和思维复盘。这篇博客我会详细记录这个阶段的思路转变、具体题目的拆解过程、常用的模板代码以及那些只有实操后才会发现的细节问题。1. 内容整体设计与思路拆解1.1 从“每日一题打卡”到“专题攻克”为什么我改变了刷题策略第一阶段我基本是“日更模式”每天打开热题榜单按顺序刷。效果有但不明显。一个月下来刷了四五十道感觉碰到新题还是没思路简单题勉强能写中等题经常要抠半小时以上。回头看问题出在“按题号刷”而不是“按知识点刷”。今天做链表明天做动态规划后天又跳到字符串知识点之间没有形成体系思维迁移的能力就上不来。第二阶段的策略改成了“专题模式”花三到五天主攻同一类题型比如本周只做双指针、下周只做动态规划基础、下下周只做二叉树遍历。表面上看效率变低了有时候一天只做两道题但一周之后同一类题目的套路很容易串起来做题速度反而提上去了。比如数组类题目翻来覆去就那几招双指针、前缀和、滑动窗口、哈希表把每一招的适用场景和代码骨架吃透之后中等题基本是“识别模式套模板处理边界”三件套。另外一个重要的变化是把“追求通过率”改成了“追求多解”。以前一道题用暴力解法过了就收工现在会刻意想一下能不能优化哈希表能不能换成原地操作递归能不能改成迭代记忆化搜索能不能优化成自底向上的动规这个过程一开始很痛苦因为意味着同样的题要做两遍三遍但一旦养成习惯对时间复杂度的敏感度会明显提升这恰恰是线上笔试最看重的素质。1.2 热题100的正确打开方式不是“刷完”而是“分层消化”力扣热题100是很多人的刷题主线但这道题单有个陷阱它只是按“热度”排序不等于按“难度梯度”递增排列。如果你像我第一阶段那样从第一题顺着往后刷很容易在第20题左右遇到一道动态规划直接心态爆炸。我的做法是把热题100分成三个梯队来处理。第一梯队是“纯送分题”比如两数之和、有效的括号、合并两个有序链表目标是10分钟内写出最优解coding熟练度拉满第二梯队是“核心模板题”比如最长回文子串、二叉树的层序遍历、岛屿数量每道题都要做到“闭着眼能写”的程度因为这些题的解法就是后面很多难题的基础组件第三梯队是“硬骨头”比如接雨水、编辑距离、正则表达式匹配我不强求一次性做出来而是先尝试20分钟没思路就看题解看懂之后合上答案自己重写第二天再独立做一遍。这个分层方法的核心逻辑是“难度匹配目标”。如果目标是秋招拿offer就要清楚大多数面试官出的题集中在热题100的第二梯队水平第三梯队的题更多出现在笔试或终面。把有限的时间优先砸在核心模板题上性价比最高。2. 核心细节解析与实操要点2.1 双指针专题从“看山是山”到“条件收敛”——以三数之和为例双指针这个技巧入门容易精通难。最经典的快慢指针、左右指针适用于数组已经有序、或者需要O(1)额外空间的场景。我在这个专题里花时间最多的一道题是15. 三数之和因为它的细节极其多写对一次不代表次次能写对。三数之和的暴力解法是三重循环时间复杂度O(n^3)一定超时。优化的核心思路是“排序 固定一个数 双指针收缩”。具体来说先把数组排序然后枚举第一个数a再用左右指针分别指向a之后区间的两端找b和c使得三数之和为0。指针移动的规则是和大于0就左指针向右移和小于0就右指针向左移等于0就记录答案后左右指针同时往里收。这道的真正难点是“去重”。排序之后相同的数会挨在一起如果不去重会得到一堆重复的三元组。比如数组里有多个-1固定第一个-1的时候已经找到了[-1, 0, 1]下次再枚举到第二个-1结果一定还是一样。处理办法很朴素在固定a和移动指针的同时跳过所有与上一个位置相同的值。这个细节看着简单但不写注释过两个月再看十有八九会忘。vectorvectorint threeSum(vectorint nums) { vectorvectorint res; sort(nums.begin(), nums.end()); int n nums.size(); for (int i 0; i n - 2; i) { if (i 0 nums[i] nums[i - 1]) continue; // 去重 int left i 1, right n - 1; while (left right) { int sum nums[i] nums[left] nums[right]; if (sum 0) { res.push_back({nums[i], nums[left], nums[right]}); while (left right nums[left] nums[left 1]) left; // 去重 while (left right nums[right] nums[right - 1]) right--; // 去重 left; right--; } else if (sum 0) { left; } else { right--; } } } return res; }强调一个小细节代码里的去重判断nums[i] nums[i-1]用的是前一个元素而不是后一个元素目的是保证至少枚举到每个不同数值的第一次出现。如果写成nums[i] nums[i1]会错误跳过一些必要组合。这个点我在面试突击时反复纠正过自己。2.2 动态规划入门状态定义是灵魂转移方程是骨架动态规划是我第二个专题的主攻对象也是很多刷题者的“劝退点”。我的经验是不要一开始就去啃难题先把“爬楼梯”“打家劫舍”“最长递增子序列”这几道经典小题做熟重点理解两个问题——dp数组里的每个位置代表什么含义当前位置的值怎么从前面的位置推过来以“打家劫舍”为例。题目是沿街偷房子不能偷相邻的两家求最大偷窃金额。状态定义可以设为dp[i]表示偷到第i间房子时能得到的最大金额。关键是转移方程到了第i间房子有两种选择——偷或者不偷。如果不偷那金额就是dp[i-1]如果偷那金额就是dp[i-2] nums[i]。取两者较大值就是dp[i]。边界条件是dp[0] nums[0]dp[1] max(nums[0], nums[1])。这道题让我明白了一个道理动态规划的难点往往不在于状态的“推演”而在于状态的“定义”。定义对了转移方程是水到渠成的事。定义错了后面全崩。还有个小技巧如果发现dp数组每个位置只用到了前两个位置的值就可以把一维数组压缩成两个变量空间复杂度从O(n)降到O(1)。刷题时这种优化不值得单独作为一道题但面试时主动提出来是很好的加分项。int rob(vectorint nums) { int n nums.size(); if (n 0) return 0; if (n 1) return nums[0]; int prev2 nums[0]; int prev1 max(nums[0], nums[1]); for (int i 2; i n; i) { int cur max(prev1, prev2 nums[i]); prev2 prev1; prev1 cur; } return prev1; }2.3 二叉树问题递归思维是核心迭代写法是进阶很多人在数组、字符串上刷得很顺一到二叉树就卡住。我总结的原因是数组题是“线性思维”而二叉树天然是“递归结构”如果脑子里没有“函数只处理当前节点剩下的交给递归”这种信念很容易陷入细节出不来。二叉树的题目我总结为四个基础遍历前序、中序、后序、层序。前三种用递归就是几行代码的事核心区别是“访问节点”和“递归调用孩子”的顺序。层序则要配合队列实现每一轮先记录当前队列长度然后只弹出 length 个节点这样就天然把每一层的数据分开了。基础遍历练熟之后很多题目就是在遍历的基础上做文章。比如“二叉树的最大深度”本质是后序遍历先算左子树深度再算右子树深度取较大值加1。比如“验证二叉搜索树”本质是中序遍历后检查序列是否严格递增。这些题目给我的感受是二叉树的题不靠死记硬背靠的是对“递归返回值是什么”的深刻理解。递归写多了之后我建议一定要练一下迭代写法。这倒不是面试一定要考而是能帮你理解递归背后的执行过程。以中序遍历为例迭代写法需要显式维护一个栈一路向左把节点压栈弹出一个节点时访问它然后把指针移向右子树。vectorint inorderTraversal(TreeNode* root) { vectorint res; stackTreeNode* stk; TreeNode* cur root; while (cur ! nullptr || !stk.empty()) { while (cur ! nullptr) { stk.push(cur); cur cur-left; } cur stk.top(); stk.pop(); res.push_back(cur-val); cur cur-right; } return res; }3. 实操过程与核心环节实现3.1 我的刷题SOP每一道题都走完五个步骤这个阶段我最满意的不是刷了多少题而是形成了一套固定做题流程。不管是一道简单的“翻转二叉树”还是需要憋很久的“正则表达式匹配”我都要求自己走完五个步骤。第一步拿到题目先不急着写代码花两分钟把题目条件圈出来尤其是数据范围。这个方法很管用比如1 nums.length 10^4就基本暗示O(n^2)算法可能勉强能过但如果有10^5这个量级就必须考虑O(nlogn)甚至O(n)的解法。很多人看见“暴力解”就直接上忽略了数据范围这个最强提示很可惜。第二步在白纸上画思路。这一步不是为了做秀而是强制自己区分“抽象想法”和“具体实现”。我会画例子随便构造一个短输入然后手动模拟一遍算法流程看能不能跑通。比如写完了“三数之和”的双指针方案就构造一个[-4, -1, -1, 0, 1, 2]手动走一遍顺便把边界条件都验一遍。第三步才是写代码。写的时候我会刻意保持“手速稳定”先搭架子函数签名、主要循环再填逻辑条件分支、边界处理最后补细节特殊情况返回、类型转换。第四步是提交但提交通过只是一个起点。我会在题解区找时间复杂度和空间复杂度最优的答案或者找思路差异大的答案对比自己和别人的代码看看差距在哪里。经常会有惊喜比如我发现同样的“接雨水”可以用单调栈、双指针、动态规划三种思路解代码从30行精简到10行对空间的利用也完全不同。第五步是记录也是最重要的一步。我已经养成了每道题都在自己的笔记中归档的习惯记录四项内容题目编号和名称我最初的思路和失败原因最优解法的核心思想这道题属于哪个专题、和哪些题目是“同思路”的亲戚题。这样过了一周、一个月复习效率会爆炸式提升。3.2 专题训练实例滑动窗口问题的统一范式滑动窗口这个专题我在第二阶段刚开始时完全摸不着头脑。题目描述千变万化什么“和为target的子数组”“最长无重复子串”“字符串排列”感觉每道题都是新题。后来做多了才发现这些题目背后有一个统一的范式。滑动窗口的核心是维护一个左指针和右指针右指针负责扩大窗口左指针负责收缩窗口。关键问题是什么时候扩大、什么时候收缩。我总结下来有两种类型一是“窗口内条件满足时收缩”比如无重复字符的最长子串二是“窗口内条件不满足时收缩”比如最小覆盖子串。以“无重复字符的最长子串”为例代码框架非常清晰。int lengthOfLongestSubstring(string s) { unordered_setchar window; int left 0, ans 0; for (int right 0; right s.size(); right) { while (window.count(s[right])) { window.erase(s[left]); left; } window.insert(s[right]); ans max(ans, right - left 1); } return ans; }这段代码的逻辑是右指针不断向右扩展如果当前的字符已经出现在窗口中就不断收缩左指针直到窗口中不再有这个字符。这样窗口始终维持“无重复”的合法状态任何时候的窗口长度就是当前的最长无重复子串长度。做多了会发现所谓刷题套路本质上是“代码框架 具体场景适配”。把框架记熟然后理解每道题对窗口合法条件的不同定义就能以不变应万变。3.3 复盘那些“想复杂了”的题简单题何以翻车第二阶段我专门做了几道简单题来打击自己的傲慢确实被打击到了。“回文数”这道题正常人能想到的做法是转成字符串双指针校验。但官方的进阶问题是“能否在不将整数转为字符串的前提下解决”这其实考查的是数字反转的思想。我一开始想复杂了试图用完全的反转整数再和原数比较但没考虑反转后整数溢出的问题。仔细一看题解才发现只需要反转一半就够了比如1221前两位12和后两位反转过来12相等就是回文。bool isPalindrome(int x) { if (x 0 || (x % 10 0 x ! 0)) return false; int reversedHalf 0; while (x reversedHalf) { reversedHalf reversedHalf * 10 x % 10; x / 10; } return x reversedHalf || x reversedHalf / 10; }这里的两个边界判断很重要所有负数都不是回文数末尾是0但本身不是0的数也不是回文数比如10反转后是01。循环条件是x reversedHalf意味着数字长度是偶数时最终会相等奇数时反转后的数会多一位去掉最后一位再比较。这道题给我的启示是简单题不等于“能打卡就行”官方题解里常藏着精妙的边界处理和数学优化值得细品。4. 常见问题与排查技巧实录4.1 刷题卡住了怎么办四步自救法刷题过程中最崩溃的时刻不是比赛没拿奖而是一道中等难度题卡了两小时各种解法都试了就是过不了普通测试用例。我用过的方法论里最有效的是“四步自救法”。第一步查数据范围重新评估时间复杂度。很多卡住的原因是选择了错误的算法框架。比如题目要求 O(logn) 但你在写 O(n) 的扫描再怎么写都对不了这时候看看数据范围中是否有“有序数组”“log级别”的暗示往往能纠正方向。第二步打日志/打印中间结果。很多人写完代码直接提交报错了才看输入输出。其实在编码阶段就应该“debug驱动”多构造几组测试数据打印每一步的关键变量看是不是符合预期。这个方法尤其适合链表、指针类的问题——这类题的边界条件肉眼很难判断打印node-val是最直接的方式。第三步回头审视边界条件。大量刷题错误不是主流程逻辑问题而是边界判断缺失。比如链表题目中head nullptr的情况数组题目中n 0和n 1的情况字符串题目中的空串。写代码之前先在注释里列出这些边界分支能减少一半以上的常见错误。第四步直接看题解但要有策略地看。我的规则是思考20分钟完全没有进展或者当前思路的实现越来越复杂且预感要出bug就不要硬扛。去看官方题解或高赞题解的“思路”,而不是直接看代码。理清思路后合上网页自己重写。这样既尊重了思考过程也避免了“背代码”的无效努力。4.2 笔试题常见的“隐藏坑”时空复杂度、输入输出与循环引用力扣的在线评测环境帮你处理了很多事情比如输入输出、内存管理但真实笔试环境就没那么友好了。这个阶段我有两次模拟线上笔试的经历收获很大也踩了不少坑。首先是时间复杂度预判。笔试系统往往同时卡时间和用例数量一个O(n^2)在数据量大的时候直接运行超时但显示的结果是“部分通过”很多人误以为是边界问题白白浪费调试时间。我的经验是在写代码之前先估算最坏复杂度如果算下来是10^8级别以上就应该主动优化算法。其次是输入输出的格式控制。力扣的样例通常会给得很清楚但笔试中经常要自己写完整的主函数包括如何处理换行、空格、多次输入。有的题目要求读取到文件末尾有的要求第一行是组数每种情况都要有一套熟悉的模板否则会花很多额外时间在“格式”上而非“算法”上。还有一个容易被忽略的坑是循环依赖和全局变量。力扣中你只需要编写一个方法但笔试中往往要求自己设计类或模块。如果在多个测试用例之间共享了全局变量而没有重置就会出现“上一个用例的数据污染下一个用例”的问题。这个坑我踩过两次排查起来非常难受——第一遍跑对了第二遍跑错了完全看不出来原因。4.3 常见问题速查表现象可能原因排查方向本地跑正确提交后报错变量未初始化 / 数组越界 / 未考虑空输入检查边界分支、在本地多测几组极端数据运行超时算法复杂度过高看数据范围重估复杂度改哈希或双指针等优化思路输出为负数整数溢出检查是否有 int 相乘或累加超限改为 long long 或先取模递归栈溢出递归深度过大改成迭代或增加递归终止条件答案重复未去重排序后跳过相同元素或用哈希集合处理哈希表遍历顺序不对对哈希表顺序的误解换用 vector 保存顺序或用 map 代替 unordered_map链表出现循环指针操作错误形成环检查每个节点的 next 赋值确认没有漏置 nullptr这张表是我踩了无数坑之后一点一点总结出来的现在已经成了我复习时的高频工具。遇到报错先对照这张表快速排查比从无到有分析问题要快得多。5. 刷题方法论的沉淀与扩展思考5.1 如何让刷题积累不“过眼云烟”笔记体系与周复盘第二个阶段结束之后我最大的焦虑是“遗忘”一个月前刷过的题现在再做可能要花同样长的时间。这说明当时的刷题没有真正转化为长期记忆。后来我找到了一个适合自己的方法——笔记体系周复盘。我用的工具很简单就是一个普通的 Markdown 文件但结构很讲究。每一道题单独一个小节内容包括题目链接、难度、我的初始思路不管对错都记、最优解法思路、复杂度分析、同类型题目链接。每周固定抽一天不刷新题只做三件事重写本周做错的题、重做上一周标记为重点的题目、把本周遇到的新题型归类到对应的专题下。这个机制坚持三周之后效果非常明显。那些本来需要看题解才能做出来的题目现在已经能独立在15分钟内完成。复习的最大价值不是“重新学一遍”而是确认“我上次学到的思路是否真的长在了脑子里”。如果某道题重做时还是卡住说明当初的理解是有漏洞的这才是重点排查对象。5.2 从力扣到真实面试的“翻译”能力很多人有一个误区力扣刷得熟面试就稳了。这个想法很危险。力扣是一个简化过的“理想环境”——输入已经帮你解析好输出只需要返回值不用管控制台格式不需要写测试用例。但真实面试完全是另一回事尤其是我经历过的几次模拟面试中让我感触最深的是“算法能力并不等同于面试表达能力”。有一个经典场景面试官问“这个解法的时间复杂度是多少为什么”如果你平时只刷题不分析很可能只回答“O(n)”而说不出推导过程。面试官不关心答案本身关心的是你的思维链路是背下来的还是真的理解了。我在面试模拟中发现如果平时做题后能用三句话向一个完全没有上下文的人解释清楚你的解法这道题才算真正吃透了。力扣题目到真实面试的另一个鸿沟是“沟通节奏”。面试中你不应该闷头写代码而是先说清楚思路让面试官确认方向再动手实现。而且做不出来的时候要敢表达比如“我现在想用滑动窗口但还没想清楚窗口收缩的时机”这句话会让面试官觉得你在思考而不是卡死了。这种软技能只能在刻意练习中培养不是靠刷题数量堆出来的。5.3 刷题之外还需要做什么以力扣为核心的拓展学习路径如果你在力扣的题目已经刷到接近“无题可做”的程度按我的估算热题100认真刷完三遍中等难度独立写出来就可以算这个状态下一步不是继续刷更新颖的难题而是应该扩展自己的知识边界。这个阶段我自己的做法是转向三个方向。第一个方向是学习标准库和语言特性。很多力扣解法都依赖特定的数据结构和API比如 C 的lower_bound、Python 的collections.Counter、Java 的PriorityQueue。深入了解这些工具的实现原理和使用技巧能让代码更简洁也更能体现工程能力。第二个方向是阅读开源项目中的算法应用。力扣题目是“伪需求”真实世界中的问题往往更复杂比如“如何在海量日志中统计热门关键词”“如何设计一个带过期时间的缓存”。这些问题通常是多个经典题型的组合但还要考虑并发、内存、可扩展性等因素。读一些知名开源项目的源码能学会在工程约束下应用算法。第三个方向是参与在线编程竞赛。和刷题不同竞赛考察的是“短时间内的思维速度 代码实现速度”这对真正的工作场景帮助很大。我自己参加过几次每周竞赛虽然排名一般但确实锻炼了“快速建模”的能力——拿到一道题三分钟内判断难度、选定算法、开始实现。结束语基于我个人经验的三个建议写到这儿第二阶段刷题记录的核心内容基本讲完了。最后再说几句我实际刷题过程中体会最深的东西。第一刷题是用来“查漏”的不是用来“表演”的。不用在意别人刷了300题还是500题关键看这些题是否覆盖了你的薄弱环节。初期可以用数量打基础但上了200题之后一定要回到专题和难度梯度上来。第二遇到难题卡住不要太早看题解。我给自己的规则是至少独立思考30分钟如果30分钟毫无输出说明已经“不会到无从下笔”的程度这时候再看题解是有价值的但如果你只思考了5分钟就翻了答案那道题永远不是你的。第三也是最重要的刷题过程记得保持记录、保持复盘。半个月后回头看自己写的代码如果觉得当时的代码写得像一坨恰恰说明这段时间是真的进步了。力扣刷题记录这个系列我打算一直写下去既是给自己一个交代也希望每一个看到这篇博客的人都能在自己的节奏里稳步前行。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。