今天是3月11号,也是我用LeetCode面试经典150这套题单刷题的第110天。刚把今晚的三道题和一次错题回顾收尾,趁着思路还热,写一篇阶段复盘。先给没接触过的朋友说清楚这套题单是什么:它是官方整理的一套面试高频题合集,总共150道,覆盖数组、字符串、链表、二叉树、图、动态规划、贪心、回溯这些面试最爱考的大类,每一道都是从历年题目里筛出来的高频代表。它的目标很明确——不让你在几千道题里大海捞针,而是用一组经过市场验证的题目,在有限时间内建立面试需要的基本盘。适合两类人:一类是准备跳槽、每天下班后临阵磨枪的开发者,另一类是还在学校、打算走工程方向但不知道从哪下手的同学。需要的基础不高,能写数组遍历和简单递归,基本就能跟上节奏。这套题单我断断续续刷了110天,中间有过想放弃的时候,也有过“看见这题就知道考什么”的爽感。这篇打卡不是单纯报进度,而是想拆一拆我踩过的坑、总结出来的刷题方法,还有几道高频题的具体思路。如果你也在这条路上,希望能给你省点试错成本。1. 面试经典150这套题单,到底好在哪1.1 为什么是150道,不是1000道很多新手入职后开始刷题,第一件事就是打开题库,按题目编号从头刷。这个姿势我太熟悉了,因为我自己就是受害者。前两周刷了大概40道,貌似很努力,实际上脑子里全是碎片:单调栈没弄懂就去碰回溯,回溯刚有点感觉又跳到图论,最后的结果是每道题都像新题,全无沉淀。面试经典150的价值在于,它把“刷题”这件事从“题海战术”变成了“重点工程”。150道这个数字不是拍脑袋定的,它基本覆盖了面试里出现频率最高的题型结构。具体来看,它大概包含这几大块:类别代表性题目类型面试出现频率数组与哈希两数之和、三数之和、合并区间极高字符串最长回文子串、有效的括号、字符串解码极高链表反转链表、环形链表、合并两个有序链表高二叉树中序遍历、最近公共祖先、层序遍历高动态规划打家劫舍、爬楼梯、编辑距离高贪心买卖股票时机、跳跃游戏中高图岛屿数量、课程表、腐烂的橘子中回溯全排列、组合总和、子集中高用这套题单相当于有人帮你划了重点。你不需要纠结“这道题面试会不会考”,只需要纠结“这道题我能不能举一反三”。我在前60天把150道过完第一轮,最大的感受不是“我会做150道题”,而是“面试题翻来覆去就那么几个套路”。1.2 和盲目刷题的区别在哪很多人刷题有一个误区:把 AC(通过所有用例)当成了唯一目标。一道题没过,就换下一道;一道题过了,也不复盘,继续下一道。这么刷一个月,AC数倒是涨了,但面试官一追问为什么,立刻卡壳。我自己走过这个弯路后总结:盲目刷题是在练习“匹配答案”,而用150题单刷题是在练习“识别模式”。举个例子,你刷了“两数之和”,如果只是背下了用哈希表,那遇到“三数之和”你还是会懵,因为三数之和的关键是排序加双指针,和两数之和思路并不一样。但如果你刷“两数之和”时理解了“空间换时间”这个核心逻辑,那么后面遇到变种题,你至少知道方向。这套150题还有一个隐藏好处:它每道题都足够典型,和面试真题的重合度很高。我去年模拟面试的时候抽过几道,几乎是原题换了个壳。“换壳题”考验的就是你拆壳的能力,而这恰恰是刷典型题能练出来的。2. Day 110这个阶段,我在刷什么2.1 当前的进度和节奏110天听起来很长,但拆开看,节奏并不算猛。我给自己定的规矩是:工作日每天至少2道,周末状态好一天4到5道。算下来总量大概在260道左右,其中150题单完整刷过两轮,另外补充了约110道同类题和部分扩展题。目前的状态是第三轮:不再按章节顺序刷,而是按套路刷,每天挑选三类题型各一道,外加错题回顾。今晚的实际安排我记录一下,方便大家感受真实节奏:时间段内容完成情况19:30-20:00回顾滑动窗口模板和两道错题完成20:00-20:40买卖股票的最佳时机 + 有效的括号完成20:40-21:30最长回文子串(中心扩展法)完成21:30-22:00写这篇阶段复盘进行中这不是打了鸡血的一天,而是很普通的一个晚上。加班到七点多,到家吃完饭后开始,中间还聊了会微信。刷题这件事,贵在每天都有接触,而不是某一天爆发六个小时。2.2 从“会做题”到“会讲题”到第110天,我发现自己的变化不在手速,而在表达。早先刷题,我写出来就完事。现在刷题,我会刻意模拟面试场景:先把题目翻译成自己的话说一遍,再讲思路、复杂度,最后才动手写代码。这个转变是因为我经历过一次真实的“翻车”:当时面试官问了一道很基础的二叉树层序遍历,我上来就写代码,结果写到一半发现忘了变量名,写得很乱。面试官打断说“你先说思路”,我一愣,嘴跟不上手。那次以后我才明白,刷题的终点不是把代码写出来,而是让人听懂你写出了什么。现在每刷一题,我都会在本地用一分钟语音复述解法逻辑。包括“这道题为什么用这个数据结构”“时间复杂度和空间复杂度分别是多少”“如果数据量扩大十倍怎么处理”。这套动作看着没什么技术含量,但对面试的帮助非常直接。3. 今晚重点复盘的几道高频题3.1 买卖股票的最佳时机:把“未来”换成“过去”这道题描述非常简单:给定一个数组,第 i 个元素是第 i 天的股票价格,只允许完成一笔交易,求最大利润。比如 [7, 1, 5, 3, 6, 4],最优是第二天买(价格1),第五天卖(价格6),利润5。新手最常见的思路是暴力法:两层循环,枚举所有“买入日”和“卖出日”,取最大差值。这个方法时间复杂度是O(n²),当数组长度超过几千就有点悬,但作为热身完全合格。暴力法的价值在于帮你验证自己理解了题目,我建议面试时可以先说暴力法保底,再谈优化,这叫“有铺垫地展示思路”。优化的核心是:不要把每个“卖出日”都拿去和所有“买入日”比较,而是只记录“今天之前的最低价格”。这样我只需要遍历一次:def maxProfit(prices): min_price = float('inf') max_profit = 0 for price in prices: if price < min_price: min_price = price profit = price - min_price if profit > max_profit: max_profit = profit return max_profit这段代码的逻辑一句话就能讲清:每到一个新价格,先更新“历史最低价”,再算“如果今天卖出能赚多少”,最后更新“最大利润”。复杂度从O(n²)降到O(n),空间O(1)。这类题的本质其实是一种“状态记录”思想——它在用“过去”的信息实时推导“当前”的答案。把这个点想通了,类似“最长递增子序列”的朴素版本你也会有感觉。3.2 有效的括号:栈的标准用法这道题在字符串分类下几乎必考。题目给一个只包含()[]{}的字符串,判断括号是否有效。有效指三类括号都正确闭合且嵌套有序。比如()[]{}有效,(]无效。这道题标准做法就是栈。关键在于:遇到左括号就入栈,遇到右括号就检查栈顶是否是对应的左括号。这里有一个非常容易踩的坑:如果栈已经空了,但来了右括号,比如输入],此时不能去取栈顶元素,否则会报错。正确写法是:def isValid(s): stack = [] pair = {')': '(', ']': '[', '}': '{'} for ch in s: if ch in pair: if not stack or stack[-1] != pair[ch]: return False stack.pop() else: stack.append(ch) return not stack我复盘这道题时给自己加了一个追问:如果不允许用额外的栈,只给一个数组,怎么做?可以用一个指针模拟栈顶,把数组当作栈。虽然实际面试很少这样要求,但这个追问能帮你更深刻理解栈的本质。很多关于括号的扩展题,比如“最长有效括号”,都是在栈的基础上加状态记录,基础不牢的话后面很难接住。3.3 最长回文子串:中心扩展不比你背的DP差这道题的经典标签是动态规划。算法书上的常规做法是二维DP,用一个dp[i][j]表示从 i 到 j 是否是回文,状态转移是dp[i][j] = (s[i] == s[j]) and dp[i+1][j-1]。这个方法逻辑清晰,但空间复杂度是O(n²),而且对新手来说状态转移方程容易写错边界。我实际推荐先用中心扩展法,它写起来更短、出错率更低。思路是:一个回文串一定有一个对称中心,这个中心可能是一个字符(奇数长度),也可能是两个字符中间(偶数长度)。遍历所有可能的中心,向两边扩展,遇到不同字符就停:def longestPalindrome(s): n = len(s) if n < 2: return s start, max_len = 0, 1 def expand(left, right): while left >= 0 and right < n and s[left] == s[right]: left -= 1 right += 1 return left + 1, right - 1 for i in range(n): l1, r1 = expand(i, i) l2, r2 = expand(i, i + 1) for l, r in ((l1, r1), (l2, r2)): if r - l + 1 > max_len: start, max_len = l, r - l + 1 return s[start:start + max_len]中心扩展的时间复杂度是O(n²),但空间只有O(1)。面试中它比DP更容易讲清楚,你不用解释那张复杂的表格是怎么填的,只要说“回文有奇数中心和偶数中心两种,我逐一尝试并对齐最长的那个”,面试官立刻能跟上。我的建议是两种方法都要会:面试优先讲中心扩展,时间充裕的话补一句“动态规划也可以做,空间换时间,但这里中心扩展空间更优”,会显得你思维灵活。4. 刷完题记不住?我的四轮刷题法4.1 第一轮:按标签顺序刷,目标只有“见过”第一轮刷题不要追求记住解法,更不要在一个题上死磕两小时。按数组、字符串、链表、树、动态规划这样的顺序,每天两道,控制在40分钟以内。如果40分钟还没头绪,直接看题解,看懂后合上答案自己重写一遍。第一轮的目标就是让大脑建立粗糙的模式库:“哦,这种求子数组的问题往往需要滑动窗口”“这种判断环路的问题用快慢指针”。这一轮我用了大约60天,中途有几天状态差只刷了一道,没关系,别断档就行。4.2 第二轮:按套路重组题单第二轮的思路是把同一个套路下的题目放在一起刷。比如连续三天只刷“双指针”:两数之和变体、三数之和、盛最多水的容器、接雨水。你会发现双指针不是一种算法,而是一类“利用单调性减少遍历次数”的思维。同理,把“滑动窗口”题放一起刷,你会总结出一个标准模板:left = 0 for right in range(n): # 扩展窗口:加入 right 位置的数据,更新窗口状态 while 窗口不满足条件: # 收缩窗口:移动 left,更新窗口状态 left += 1 # 此时窗口满足条件,更新答案这套模板几乎适用于所有连续子数组、子串问题。二刷的核心不是做题,而是总结出这样的“口诀”。我为每类题型都准备了一个单独文档,记录模板和易错边界。比如二分查找的边界条件我至少写错过十次,二刷时专门用一页整理了“左闭右开和左闭右闭的退出条件”对比,之后再遇到二分题,直接套对比表,基本不会错。4.3 第三轮:限时手写第三轮开始给自己上压力。每道题给自己25分钟,和面试题时间对齐。期间不能看题解,不能翻笔记,写完当场口头讲解一遍复杂度。这一步很痛苦,但非常有效。我前两轮觉得自己会了,一到限时环境就原形毕露:要么边界写错,要么忘了处理空数组,要么变量命名混乱。第三轮就是把这些毛病在正式面试前逼出来。我目前就处在这个阶段。4.4 第四轮:错题和模板输出最后一轮不按题单走,而是按“错题本”走。我每次复盘后会把错题整理到一张表格,标清楚错误原因:是思路错了、边界漏了、还是复杂度算错。每周抽一个晚上,不刷新题,专门把错题本里的题重写一遍。这个习惯坚持了有五周,效果非常明显。很多题第二周重写时,能明显感觉到“肌肉记忆”在形成。这里说的肌肉记忆不是背代码,而是知道第一步该做什么:先判断数据结构,再确定遍历方式,最后优化复杂度。5. 常见问题实录5.1 一刷就懂,三天就忘这是我在评论区看到最多的问题,也是我自己第一轮的真实状态。今天看懂题解,三天后碰到原题,脑袋空白。原因很简单:你只是在“看”题解,没有“拆”题解。看明白和能写出来之间,隔着一道“主动回忆”的鸿沟。解决办法是费曼式复述:看完题解后,别立刻抄写,先合上答案,用自己的话把解法写出来,包括每一步为什么这样做。如果中间卡住,再打开答案,把卡住的地方标记为红色。这一道题花的时间比直接抄答案多20分钟,但记住率可能提高三倍以上。另外,按“套路分组”刷题也能有效对抗遗忘,因为同一套路连续出现,大脑会把它当做一个知识块而不是孤立题目。5.2 面试一紧张就写不出来很多人刷题时很顺,一到白板或在线编辑器就手抖。我自己的经验是,紧张感主要来自“不知道下一步该干什么”的不确定性。解决办法是在写代码前强制自己说出完整的执行路径。比如做“有效的括号”,先对自己说:建栈,遍历,遇到左括号入栈,遇到右括号判断匹配,最后看栈是否为空。说完再动手。这套仪式看着傻,但能把“失控感”拉回来,因为大脑在出声时已经预演了一遍逻辑。如果面试官允许,还可以先在注释里写出关键步骤,再填代码。这不代表你水平差,反而会让面试官觉得你思路清晰。我最怕的其实是另一种情况:题目没见过,脑子里连方向都没有。这时候我的备用策略是“暴力法保底”。先说出最简单的解法,哪怕复杂度很高,至少证明你读懂了题,然后再讨论怎么优化。很多时候面试官要的就是这个推导过程。5.3 150道刷完了,接下来呢如果你已经稳定刷完150题,恭喜,你已经超过了多数候选人。接下来两条路:一是补齐薄弱环节,比如动态规划不好就集中刷20道DP题,直到能闭眼写出“爬楼梯”“打家劫舍”“最长递增子序列”这类基础题的多种解法。二是转向模拟面试,用限时写题、讲题的方式检验真实水平。同时也可以关注一些高频扩展题,比如“编辑距离”“接雨水”“LRU缓存”这类经典题之外的进阶题。记住一点:刷题的目的是形成解决方案库,而不是表演题量。5.4 常见问题速查表问题我的做法效果记不住解法看完题解后合上重写,卡住处标红记忆持久度明显提升不知道从哪开始先用暴力法保底,再讨论优化至少不冷场每天刷几题合适工作日2道,周末4-5道长期可持续纠结要不要刷Hard偶尔做一道,不硬刚保持信心又不缺失挑战做错题要不要整理用表格记录错误原因,每周重写错题复发率下降该不该背模板背结构,不背代码面试时灵活变通6. 给还在前60天的朋友几句实在话6.1 每天2道题足够,不需要刷到凌晨我见过不少朋友,刚立Flag时猛刷一晚上5道题,第二天直接累到放弃。刷题是长跑,不是冲刺。110天里我有十天左右只刷了一道,甚至有一天因为项目上线没刷,第二天补上。连续、稳定、可承受,这三个词比“每天三小时”更重要。你的目标是“坚持到面试那天”,不是“一个月刷完”。6.2 卡题超过40分钟直接看题解,别硬刚第一轮刷题时,我经常在一道Medium上死磕一个半小时,最后身心俱疲。后来定了个规矩:40分钟没思路,立刻看题解,看懂后自己再写一遍。为什么40分钟?因为面试时一道题通常给到25-35分钟,超过这个时间说明你当前的模式库匹配不上这题,继续硬刚的边际收益很低。看题解不是偷懒,是学习新套路,关键是你得真的“看懂后再写”,而不是“抄完就关”。6.3 笔记不要抄代码,要记一句话结构很多人做笔记会把题解完整贴下来,看起来很充实,其实复习时根本不会看。我现在每一题只写一行“题眼”:比如“三数之和——排序+固定一位+双指针”“最长回文子串——中心扩展,区分奇偶中心”“有效的括号——栈匹配,注意空栈判断”。一行字包含了这道题的核心套路,复习时扫一遍就能回忆起整个思路。这样做的另一个好处是,你会被迫提炼和总结,而总结本身就是一种深度加工,加工得越深,记得越牢。最后再分享一个小习惯:每周挑一个固定时间,把本周做错的题重做一遍,并且假装自己在面试现场,对镜子讲一遍思路。这个动作非常土,但真的有用。我在第90天左右开始这么做,两周后就感觉自己讲题明显流利了很多。刷题到后期,拼的已经不是谁会做,而是谁能在压力下稳定输出。希望这篇Day 110的复盘能给你一点参考,刷得快的别焦虑,刷得慢的也别慌,每天往前走两步,时间会给你答案。
今天是3月11号,也是我用LeetCode面试经典150这套题单刷题的第110天。刚把今晚的三道题和一次错题回顾收尾,趁着思路还热,写一篇阶段复盘。先给没接触过的朋友说清楚这套题单是什么:它是官方整理的一套面试高频题合集,总共150道,覆盖数组、字符串、链表、二叉树、图、动态规划、贪心、回溯这些面试最爱考的大类,每一道都是从历年题目里筛出来的高频代表。它的目标很明确——不让你在几千道题里大海捞针,而是用一组经过市场验证的题目,在有限时间内建立面试需要的基本盘。适合两类人:一类是准备跳槽、每天下班后临阵磨枪的开发者,另一类是还在学校、打算走工程方向但不知道从哪下手的同学。需要的基础不高,能写数组遍历和简单递归,基本就能跟上节奏。这套题单我断断续续刷了110天,中间有过想放弃的时候,也有过“看见这题就知道考什么”的爽感。这篇打卡不是单纯报进度,而是想拆一拆我踩过的坑、总结出来的刷题方法,还有几道高频题的具体思路。如果你也在这条路上,希望能给你省点试错成本。1. 面试经典150这套题单,到底好在哪1.1 为什么是150道,不是1000道很多新手入职后开始刷题,第一件事就是打开题库,按题目编号从头刷。这个姿势我太熟悉了,因为我自己就是受害者。前两周刷了大概40道,貌似很努力,实际上脑子里全是碎片:单调栈没弄懂就去碰回溯,回溯刚有点感觉又跳到图论,最后的结果是每道题都像新题,全无沉淀。面试经典150的价值在于,它把“刷题”这件事从“题海战术”变成了“重点工程”。150道这个数字不是拍脑袋定的,它基本覆盖了面试里出现频率最高的题型结构。具体来看,它大概包含这几大块:类别代表性题目类型面试出现频率数组与哈希两数之和、三数之和、合并区间极高字符串最长回文子串、有效的括号、字符串解码极高链表反转链表、环形链表、合并两个有序链表高二叉树中序遍历、最近公共祖先、层序遍历高动态规划打家劫舍、爬楼梯、编辑距离高贪心买卖股票时机、跳跃游戏中高图岛屿数量、课程表、腐烂的橘子中回溯全排列、组合总和、子集中高用这套题单相当于有人帮你划了重点。你不需要纠结“这道题面试会不会考”,只需要纠结“这道题我能不能举一反三”。我在前60天把150道过完第一轮,最大的感受不是“我会做150道题”,而是“面试题翻来覆去就那么几个套路”。1.2 和盲目刷题的区别在哪很多人刷题有一个误区:把 AC(通过所有用例)当成了唯一目标。一道题没过,就换下一道;一道题过了,也不复盘,继续下一道。这么刷一个月,AC数倒是涨了,但面试官一追问为什么,立刻卡壳。我自己走过这个弯路后总结:盲目刷题是在练习“匹配答案”,而用150题单刷题是在练习“识别模式”。举个例子,你刷了“两数之和”,如果只是背下了用哈希表,那遇到“三数之和”你还是会懵,因为三数之和的关键是排序加双指针,和两数之和思路并不一样。但如果你刷“两数之和”时理解了“空间换时间”这个核心逻辑,那么后面遇到变种题,你至少知道方向。这套150题还有一个隐藏好处:它每道题都足够典型,和面试真题的重合度很高。我去年模拟面试的时候抽过几道,几乎是原题换了个壳。“换壳题”考验的就是你拆壳的能力,而这恰恰是刷典型题能练出来的。2. Day 110这个阶段,我在刷什么2.1 当前的进度和节奏110天听起来很长,但拆开看,节奏并不算猛。我给自己定的规矩是:工作日每天至少2道,周末状态好一天4到5道。算下来总量大概在260道左右,其中150题单完整刷过两轮,另外补充了约110道同类题和部分扩展题。目前的状态是第三轮:不再按章节顺序刷,而是按套路刷,每天挑选三类题型各一道,外加错题回顾。今晚的实际安排我记录一下,方便大家感受真实节奏:时间段内容完成情况19:30-20:00回顾滑动窗口模板和两道错题完成20:00-20:40买卖股票的最佳时机 + 有效的括号完成20:40-21:30最长回文子串(中心扩展法)完成21:30-22:00写这篇阶段复盘进行中这不是打了鸡血的一天,而是很普通的一个晚上。加班到七点多,到家吃完饭后开始,中间还聊了会微信。刷题这件事,贵在每天都有接触,而不是某一天爆发六个小时。2.2 从“会做题”到“会讲题”到第110天,我发现自己的变化不在手速,而在表达。早先刷题,我写出来就完事。现在刷题,我会刻意模拟面试场景:先把题目翻译成自己的话说一遍,再讲思路、复杂度,最后才动手写代码。这个转变是因为我经历过一次真实的“翻车”:当时面试官问了一道很基础的二叉树层序遍历,我上来就写代码,结果写到一半发现忘了变量名,写得很乱。面试官打断说“你先说思路”,我一愣,嘴跟不上手。那次以后我才明白,刷题的终点不是把代码写出来,而是让人听懂你写出了什么。现在每刷一题,我都会在本地用一分钟语音复述解法逻辑。包括“这道题为什么用这个数据结构”“时间复杂度和空间复杂度分别是多少”“如果数据量扩大十倍怎么处理”。这套动作看着没什么技术含量,但对面试的帮助非常直接。3. 今晚重点复盘的几道高频题3.1 买卖股票的最佳时机:把“未来”换成“过去”这道题描述非常简单:给定一个数组,第 i 个元素是第 i 天的股票价格,只允许完成一笔交易,求最大利润。比如 [7, 1, 5, 3, 6, 4],最优是第二天买(价格1),第五天卖(价格6),利润5。新手最常见的思路是暴力法:两层循环,枚举所有“买入日”和“卖出日”,取最大差值。这个方法时间复杂度是O(n²),当数组长度超过几千就有点悬,但作为热身完全合格。暴力法的价值在于帮你验证自己理解了题目,我建议面试时可以先说暴力法保底,再谈优化,这叫“有铺垫地展示思路”。优化的核心是:不要把每个“卖出日”都拿去和所有“买入日”比较,而是只记录“今天之前的最低价格”。这样我只需要遍历一次:def maxProfit(prices): min_price = float('inf') max_profit = 0 for price in prices: if price < min_price: min_price = price profit = price - min_price if profit > max_profit: max_profit = profit return max_profit这段代码的逻辑一句话就能讲清:每到一个新价格,先更新“历史最低价”,再算“如果今天卖出能赚多少”,最后更新“最大利润”。复杂度从O(n²)降到O(n),空间O(1)。这类题的本质其实是一种“状态记录”思想——它在用“过去”的信息实时推导“当前”的答案。把这个点想通了,类似“最长递增子序列”的朴素版本你也会有感觉。3.2 有效的括号:栈的标准用法这道题在字符串分类下几乎必考。题目给一个只包含()[]{}的字符串,判断括号是否有效。有效指三类括号都正确闭合且嵌套有序。比如()[]{}有效,(]无效。这道题标准做法就是栈。关键在于:遇到左括号就入栈,遇到右括号就检查栈顶是否是对应的左括号。这里有一个非常容易踩的坑:如果栈已经空了,但来了右括号,比如输入],此时不能去取栈顶元素,否则会报错。正确写法是:def isValid(s): stack = [] pair = {')': '(', ']': '[', '}': '{'} for ch in s: if ch in pair: if not stack or stack[-1] != pair[ch]: return False stack.pop() else: stack.append(ch) return not stack我复盘这道题时给自己加了一个追问:如果不允许用额外的栈,只给一个数组,怎么做?可以用一个指针模拟栈顶,把数组当作栈。虽然实际面试很少这样要求,但这个追问能帮你更深刻理解栈的本质。很多关于括号的扩展题,比如“最长有效括号”,都是在栈的基础上加状态记录,基础不牢的话后面很难接住。3.3 最长回文子串:中心扩展不比你背的DP差这道题的经典标签是动态规划。算法书上的常规做法是二维DP,用一个dp[i][j]表示从 i 到 j 是否是回文,状态转移是dp[i][j] = (s[i] == s[j]) and dp[i+1][j-1]。这个方法逻辑清晰,但空间复杂度是O(n²),而且对新手来说状态转移方程容易写错边界。我实际推荐先用中心扩展法,它写起来更短、出错率更低。思路是:一个回文串一定有一个对称中心,这个中心可能是一个字符(奇数长度),也可能是两个字符中间(偶数长度)。遍历所有可能的中心,向两边扩展,遇到不同字符就停:def longestPalindrome(s): n = len(s) if n < 2: return s start, max_len = 0, 1 def expand(left, right): while left >= 0 and right < n and s[left] == s[right]: left -= 1 right += 1 return left + 1, right - 1 for i in range(n): l1, r1 = expand(i, i) l2, r2 = expand(i, i + 1) for l, r in ((l1, r1), (l2, r2)): if r - l + 1 > max_len: start, max_len = l, r - l + 1 return s[start:start + max_len]中心扩展的时间复杂度是O(n²),但空间只有O(1)。面试中它比DP更容易讲清楚,你不用解释那张复杂的表格是怎么填的,只要说“回文有奇数中心和偶数中心两种,我逐一尝试并对齐最长的那个”,面试官立刻能跟上。我的建议是两种方法都要会:面试优先讲中心扩展,时间充裕的话补一句“动态规划也可以做,空间换时间,但这里中心扩展空间更优”,会显得你思维灵活。4. 刷完题记不住?我的四轮刷题法4.1 第一轮:按标签顺序刷,目标只有“见过”第一轮刷题不要追求记住解法,更不要在一个题上死磕两小时。按数组、字符串、链表、树、动态规划这样的顺序,每天两道,控制在40分钟以内。如果40分钟还没头绪,直接看题解,看懂后合上答案自己重写一遍。第一轮的目标就是让大脑建立粗糙的模式库:“哦,这种求子数组的问题往往需要滑动窗口”“这种判断环路的问题用快慢指针”。这一轮我用了大约60天,中途有几天状态差只刷了一道,没关系,别断档就行。4.2 第二轮:按套路重组题单第二轮的思路是把同一个套路下的题目放在一起刷。比如连续三天只刷“双指针”:两数之和变体、三数之和、盛最多水的容器、接雨水。你会发现双指针不是一种算法,而是一类“利用单调性减少遍历次数”的思维。同理,把“滑动窗口”题放一起刷,你会总结出一个标准模板:left = 0 for right in range(n): # 扩展窗口:加入 right 位置的数据,更新窗口状态 while 窗口不满足条件: # 收缩窗口:移动 left,更新窗口状态 left += 1 # 此时窗口满足条件,更新答案这套模板几乎适用于所有连续子数组、子串问题。二刷的核心不是做题,而是总结出这样的“口诀”。我为每类题型都准备了一个单独文档,记录模板和易错边界。比如二分查找的边界条件我至少写错过十次,二刷时专门用一页整理了“左闭右开和左闭右闭的退出条件”对比,之后再遇到二分题,直接套对比表,基本不会错。4.3 第三轮:限时手写第三轮开始给自己上压力。每道题给自己25分钟,和面试题时间对齐。期间不能看题解,不能翻笔记,写完当场口头讲解一遍复杂度。这一步很痛苦,但非常有效。我前两轮觉得自己会了,一到限时环境就原形毕露:要么边界写错,要么忘了处理空数组,要么变量命名混乱。第三轮就是把这些毛病在正式面试前逼出来。我目前就处在这个阶段。4.4 第四轮:错题和模板输出最后一轮不按题单走,而是按“错题本”走。我每次复盘后会把错题整理到一张表格,标清楚错误原因:是思路错了、边界漏了、还是复杂度算错。每周抽一个晚上,不刷新题,专门把错题本里的题重写一遍。这个习惯坚持了有五周,效果非常明显。很多题第二周重写时,能明显感觉到“肌肉记忆”在形成。这里说的肌肉记忆不是背代码,而是知道第一步该做什么:先判断数据结构,再确定遍历方式,最后优化复杂度。5. 常见问题实录5.1 一刷就懂,三天就忘这是我在评论区看到最多的问题,也是我自己第一轮的真实状态。今天看懂题解,三天后碰到原题,脑袋空白。原因很简单:你只是在“看”题解,没有“拆”题解。看明白和能写出来之间,隔着一道“主动回忆”的鸿沟。解决办法是费曼式复述:看完题解后,别立刻抄写,先合上答案,用自己的话把解法写出来,包括每一步为什么这样做。如果中间卡住,再打开答案,把卡住的地方标记为红色。这一道题花的时间比直接抄答案多20分钟,但记住率可能提高三倍以上。另外,按“套路分组”刷题也能有效对抗遗忘,因为同一套路连续出现,大脑会把它当做一个知识块而不是孤立题目。5.2 面试一紧张就写不出来很多人刷题时很顺,一到白板或在线编辑器就手抖。我自己的经验是,紧张感主要来自“不知道下一步该干什么”的不确定性。解决办法是在写代码前强制自己说出完整的执行路径。比如做“有效的括号”,先对自己说:建栈,遍历,遇到左括号入栈,遇到右括号判断匹配,最后看栈是否为空。说完再动手。这套仪式看着傻,但能把“失控感”拉回来,因为大脑在出声时已经预演了一遍逻辑。如果面试官允许,还可以先在注释里写出关键步骤,再填代码。这不代表你水平差,反而会让面试官觉得你思路清晰。我最怕的其实是另一种情况:题目没见过,脑子里连方向都没有。这时候我的备用策略是“暴力法保底”。先说出最简单的解法,哪怕复杂度很高,至少证明你读懂了题,然后再讨论怎么优化。很多时候面试官要的就是这个推导过程。5.3 150道刷完了,接下来呢如果你已经稳定刷完150题,恭喜,你已经超过了多数候选人。接下来两条路:一是补齐薄弱环节,比如动态规划不好就集中刷20道DP题,直到能闭眼写出“爬楼梯”“打家劫舍”“最长递增子序列”这类基础题的多种解法。二是转向模拟面试,用限时写题、讲题的方式检验真实水平。同时也可以关注一些高频扩展题,比如“编辑距离”“接雨水”“LRU缓存”这类经典题之外的进阶题。记住一点:刷题的目的是形成解决方案库,而不是表演题量。5.4 常见问题速查表问题我的做法效果记不住解法看完题解后合上重写,卡住处标红记忆持久度明显提升不知道从哪开始先用暴力法保底,再讨论优化至少不冷场每天刷几题合适工作日2道,周末4-5道长期可持续纠结要不要刷Hard偶尔做一道,不硬刚保持信心又不缺失挑战做错题要不要整理用表格记录错误原因,每周重写错题复发率下降该不该背模板背结构,不背代码面试时灵活变通6. 给还在前60天的朋友几句实在话6.1 每天2道题足够,不需要刷到凌晨我见过不少朋友,刚立Flag时猛刷一晚上5道题,第二天直接累到放弃。刷题是长跑,不是冲刺。110天里我有十天左右只刷了一道,甚至有一天因为项目上线没刷,第二天补上。连续、稳定、可承受,这三个词比“每天三小时”更重要。你的目标是“坚持到面试那天”,不是“一个月刷完”。6.2 卡题超过40分钟直接看题解,别硬刚第一轮刷题时,我经常在一道Medium上死磕一个半小时,最后身心俱疲。后来定了个规矩:40分钟没思路,立刻看题解,看懂后自己再写一遍。为什么40分钟?因为面试时一道题通常给到25-35分钟,超过这个时间说明你当前的模式库匹配不上这题,继续硬刚的边际收益很低。看题解不是偷懒,是学习新套路,关键是你得真的“看懂后再写”,而不是“抄完就关”。6.3 笔记不要抄代码,要记一句话结构很多人做笔记会把题解完整贴下来,看起来很充实,其实复习时根本不会看。我现在每一题只写一行“题眼”:比如“三数之和——排序+固定一位+双指针”“最长回文子串——中心扩展,区分奇偶中心”“有效的括号——栈匹配,注意空栈判断”。一行字包含了这道题的核心套路,复习时扫一遍就能回忆起整个思路。这样做的另一个好处是,你会被迫提炼和总结,而总结本身就是一种深度加工,加工得越深,记得越牢。最后再分享一个小习惯:每周挑一个固定时间,把本周做错的题重做一遍,并且假装自己在面试现场,对镜子讲一遍思路。这个动作非常土,但真的有用。我在第90天左右开始这么做,两周后就感觉自己讲题明显流利了很多。刷题到后期,拼的已经不是谁会做,而是谁能在压力下稳定输出。希望这篇Day 110的复盘能给你一点参考,刷得快的别焦虑,刷得慢的也别慌,每天往前走两步,时间会给你答案。