
1. 项目背景与核心价值面试150这个标题乍看简单实则暗含了程序员求职备战的核心方法论。作为经历过三次职业跳槽的老兵我深刻理解系统性刷题对技术面试的决定性作用。这个系列记录了我用七周时间攻克150道高频算法题的完整历程本周进入最关键的冲刺阶段。不同于普通的刷题记录本系列特别注重题目之间的内在知识关联真实面试中的变形考法时间/空间复杂度优化的临界点白板编码时的思维显性化技巧本周精选的21道题目覆盖了字符串处理、树形DP、单调栈等大厂必考题型其中至少有5道是近半年字节跳动和腾讯的真实面试原题。我将通过解题模板、错题本和性能对比三个维度带你看透题目背后的考察逻辑。2. 本周重点题型解析2.1 字符串处理三剑客KMP算法实战在解决 实现strStr() 时暴力解法O(mn)的时间复杂度在面经中直接淘汰。通过构建next数组def getNext(p: str): next [0] * len(p) j 0 for i in range(1, len(p)): while j 0 and p[i] ! p[j]: j next[j-1] if p[i] p[j]: j 1 next[i] j return next关键点next数组表示的是最长相同前后缀不是部分同学误解的失败跳转位置。面试官常要求手推aabaaac的next数组构建过程。滑动窗口模板处理 最小覆盖子串 时维护两个哈希表valid计数器的套路可以解决90%的子串问题def minWindow(s: str, t: str) - str: need collections.defaultdict(int) window collections.defaultdict(int) for c in t: need[c] 1 left right 0 valid 0 start, length 0, float(inf) while right len(s): # 右扩窗口 c s[right] right 1 if c in need: window[c] 1 if window[c] need[c]: valid 1 # 左缩条件 while valid len(need): if right - left length: start left length right - left # 左缩窗口 d s[left] left 1 if d in need: if window[d] need[d]: valid - 1 window[d] - 1 return s[start:startlength] if length ! float(inf) else 2.2 树形DP的破局思路遇到 打家劫舍III 这类问题时常规DFS会陷入重复计算的泥潭。采用后序遍历状态记录def rob(root: TreeNode) - int: def _rob(node): if not node: return (0, 0) left _rob(node.left) right _rob(node.right) # 当前节点不偷 左右子节点偷或不偷的最大值之和 not_rob max(left) max(right) # 当前节点偷 左右子节点不偷的值当前节点值 rob left[0] right[0] node.val return (not_rob, rob) return max(_rob(root))避坑指南返回值用元组比两个全局变量更安全面试时建议先说明状态定义再写代码。遇到过有面试官故意问为什么不用贪心从叶子节点开始抢来考察对DP的理解深度。3. 高频考点深度剖析3.1 单调栈的四种变体通过 柱状图中最大的矩形 总结出单调栈的解题模板找最近较小值维护单调递增栈找最近较大值维护单调递减栈边界处理首尾补0避免空栈判断宽度计算出栈时当前索引与栈顶索引的差值-1def largestRectangleArea(heights: List[int]) - int: heights [0] heights [0] stack [] res 0 for i in range(len(heights)): while stack and heights[stack[-1]] heights[i]: h heights[stack.pop()] w i - stack[-1] - 1 res max(res, h * w) stack.append(i) return res3.2 位运算的骚操作只出现一次的数字III 要求找出两个唯一数通过异或找到差异位后分组def singleNumber(nums: List[int]) - List[int]: xor 0 for num in nums: xor ^ num mask 1 while (xor mask) 0: mask 1 a, b 0, 0 for num in nums: if num mask: a ^ num else: b ^ num return [a, b]面试陷阱有候选人说直接用Counter就行这完全背离了考察位运算的本意。建议在面试时主动说出时间O(n)空间O(1)的优势。4. 面试实战技巧4.1 白板编码的黄金法则三明治沟通法先复述题意确认理解5%时间举例说明解法思路35%时间编码时同步解释关键变量50%时间测试用例验证10%时间变量命名技巧滑动窗口用left/right代替i/jDP状态用rob/not_rob比dp[0]/dp[1]更直观全局结果用res而非ans外企面试常见4.2 复杂度分析的加分项遇到 乘积最大子数组 时不仅要说出O(n)时间复杂度还要解释因为维护了imin/imax两个状态变量在遍历时同时考虑了当前值的正负影响。当遇到负数时交换imin/imax的操作保证了状态转移的正确性这个技巧同样适用于需要维护极值的动态规划问题。5. 错题本精华5.1 易错点TOP3单调栈宽度计算错误i - stack[-1]正确i - stack[-1] - 1因为栈顶元素已弹出树形DP状态返回错误用类成员变量存储结果正确返回元组使函数保持纯函数特性位运算mask生成错误mask xor -xor Python负数存储特殊正确while循环找到最右差异位5.2 高频Follow-up问题如果输入规模扩大到10^7怎么办考察点外部排序/流式处理思想标准回答可以考虑分块处理归并的思路...如何用多线程优化这个算法考察点并行计算分治策略标准回答像归并排序这种可分治的问题...如果内存限制为O(1)呢考察点原地算法技巧标准回答对于矩阵旋转这类问题...这套方法论帮助我在最近面试中拿下字节3-1和阿里P7的offer建议把每个题目的变形考法都写在代码注释里。比如KMP算法在面试中可能要求改成返回所有匹配位置这时候在next数组的构建阶段就需要记录完整匹配信息。