推荐阅读
- 先读高频题型概览与标准模板
- 再按分类刷题并记录可复用思路
- 最后复盘错题,形成个人题库
这里是 Hot100 系列的合集页。每题统一按 ACERS 模板写作,强调“题解模板化 + 工程场景迁移 + 多语言实现”。 推荐阅读 先从数组 / 哈希 / 前缀和等高频主题开始 每题掌握一个可复用的“方法模型” 做完题后再回到工程场景,强化迁移能力
题目要求 输入输出 输入:整数 n 含义:爬到第 n 阶楼顶 每次可以爬 1 或 2 阶 输出:返回到达楼顶的不同走法数量 约束:1 <= n <= 45 示例 输入:n = 2 输出:2 解释:1+1,2 输入:n = 3 输出:3 解释:1+1+1,1+2,2+1 这篇只用 Python,从 dp[i] 的含义一步一步推出最终代码。 从 n = 3 的最后一步开始 先看最小能暴露转移的例子: n = 3 到第 3 阶的最后一步只可能来自: 第 2 阶,再走 1 阶 第 1 阶,再走 2 阶 所以“到第 3 阶的方法数”不是凭空算出来的,而是来自两个更小的位置。 Step 1:先定义更小的问题 直接问“到第 n 阶有几种走法”太大。先定义: dp[i] = 到达第 i 阶的方法数 注意这里的 i 是楼梯位置,不是数组下标含义上的第几个元素。 ...
题目要求 输入输出 输入:整数数组 cost cost[i] 表示踩到第 i 阶的代价 每次可以爬 1 或 2 阶 可以从下标 0 或下标 1 开始 输出:返回到达楼顶的最小花费 约束:2 <= cost.length <= 1000,0 <= cost[i] <= 999 示例 输入:cost = [10,15,20] 输出:15 解释:从下标 1 开始,付 15 后直接到达 top 输入:cost = [1,100,1,1,1,100,1,1,100,1] 输出:6 从 [10,15,20] 的 top 位置开始 先看最小例子: cost = [10,15,20] 楼顶不是下标 2,而是在最后一阶之后的位置,可以记为位置 3。 到达 top 位置 3 的最后一步只可能来自: 位置 2,付 cost[2] 位置 1,付 cost[1] 这题最容易错的地方就在这里:我们要求的是“到达 top 的花费”,不是“到达最后一个下标的花费”。 ...
副标题 / 摘要 216. 组合总和 III 给回溯再加了一条关键约束:不仅总和要命中,组合长度也必须恰好等于 k。这会把问题变成一个很干净的“固定长度组合搜索”。 预计阅读时长:12~15 分钟 标签:回溯、固定长度、剪枝、组合搜索 SEO 关键词:Combination Sum III, 组合总和 III, 固定长度回溯, k 个数, 剪枝, LeetCode 216 元描述:从题目本身推导 LeetCode 216 的稳定解法,真正理解固定长度 k、有界候选集 1..9 与只能使用一次的回溯模型。 A — Algorithm(题目与算法) 题目还原 找出所有满足条件的组合,使得: 从 1 到 9 中选数 一共恰好选 k 个数 这些数的和等于 n 每个数最多只能使用一次 返回所有可能的合法组合。 答案中不能包含重复组合,组合顺序不重要。 输入输出 名称 类型 描述 k int 需要选出的数字个数 n int 目标和 返回 int[][] 所有长度为 k 且和为 n 的合法组合 示例 1 输入:k = 3, n = 7 输出:[[1,2,4]] 示例 2 输入:k = 3, n = 9 输出:[[1,2,6],[1,3,5],[2,3,4]] 示例 3 输入:k = 4, n = 1 输出:[] 约束 2 <= k <= 9 1 <= n <= 60 目标读者 已经理解 39、40,现在准备继续叠加“长度必须恰好是 k”这个新约束的学习者 会写基本 DFS,但经常把“目标和”与“固定长度”混在一起判断的读者 想掌握固定长度组合搜索模板的开发者 背景 / 动机 这道题很适合作为 39 和 40 之后的下一题,因为它保留了回溯骨架,但搜索空间进一步收紧了: ...
副标题 / 摘要 如果说 39. 组合总和 教你“当前值还能继续用”,那 40. 组合总和 II 教你的就是下一层升级:数组里会出现重复值、每个位置只能用一次、去重必须发生在正确的树层上。 预计阅读时长:14~16 分钟 标签:回溯、去重、剪枝、组合搜索 SEO 关键词:Combination Sum II, 组合总和 II, 回溯, 同层去重, 剪枝, LeetCode 40 元描述:从题目本身一步一步推出 LeetCode 40 的稳定解法,真正理解排序、i + 1 递归和“同层去重”规则。 A — Algorithm(题目与算法) 题目还原 给定一个候选数组 candidates 和一个目标值 target, 找出所有和为 target 的不同组合,并以列表形式返回。 candidates 中的每个数字在每个组合里 最多只能使用一次。 最终答案中不能包含重复组合。 输入输出 名称 类型 描述 candidates int[] 候选数组,允许出现重复值 target int 目标和 返回 int[][] 所有和为 target 的不同组合 示例 1 输入:candidates = [10,1,2,7,6,1,5], target = 8 输出: [ [1,1,6], [1,2,5], [1,7], [2,6] ] 示例 2 输入:candidates = [2,5,2,1,2], target = 5 输出: [ [1,2,2], [5] ] 约束 1 <= candidates.length <= 100 1 <= candidates[i] <= 50 1 <= target <= 30 目标读者 已经做完 39. 组合总和,想继续搞清“不能重复选”之后模板怎么变的学习者 会写回溯框架,但一碰到输入里有重复值就容易写乱去重逻辑的读者 想真正掌握“同层去重”而不是硬背一句 if i > start and ... 的开发者 背景 / 动机 这道题是 39 的自然下一题,因为它同时改了两条规则: ...
副标题 / 摘要 Clone Graph 不是单纯的图遍历题,而是“带环对象图的深拷贝”题。真正的关键不是能不能走完图,而是如何保证每个原节点只克隆一次,并且所有边都指向克隆图中的新节点。 预计阅读时长:12~15 分钟 标签:图、DFS、BFS、哈希表、深拷贝 SEO 关键词:克隆图, Clone Graph, 图深拷贝, LeetCode 133, DFS, BFS 元描述:通过“原节点 -> 新节点”映射表实现无向图深拷贝,讲清 DFS/BFS、环处理、复杂度与多语言代码。 目标读者 刷 LeetCode 图论题、希望掌握“深拷贝 + visited/map”模板的学习者 需要复制对象图、工作流图、拓扑结构的工程师 经常在“图遍历”和“对象复制”之间混淆的开发者 背景 / 动机 很多同学第一次做这题,会把它当成普通遍历题: DFS 一遍 BFS 一遍 把值抄过去 但真正难点在于: 图里可能有环 同一个节点可能从多条路径访问到 复制出来的新图,所有邻居必须指向“新节点”,不能混入旧节点引用 所以这题本质上是: 带环对象图的深拷贝问题 这类模式在工程里也很常见: 复制流程编排图 克隆编辑器里的节点网络 复制依赖关系图做快照 核心概念 深拷贝:返回的新图里每个节点都必须是新建对象 节点身份:判断“是不是同一个节点”看的是对象身份 / 引用,不只是 val 邻接关系保持:新图的边结构必须与原图完全一致 映射表:原节点 -> 克隆节点,既防止死循环,也防止重复创建 A — Algorithm(题目与算法) 题目重述 给定一个无向连通图中某个节点 node 的引用,请返回这个图的深拷贝。 每个节点结构如下: class Node { public int val; public List<Node> neighbors; } 题目测试用例使用邻接表表示图。 如果图不为空,给定节点总是值为 1 的节点。 ...
副标题 / 摘要 LeetCode 100 的关键不在“会不会遍历树”,而在“能不能把两棵树当成一对一对的节点同步比较”。本文按 ACERS 结构拆解同步递归的判断合同、BFS 成对校验写法,以及工程里常见的结构等价判断场景。 预计阅读时长:9~11 分钟 标签:二叉树、DFS、BFS、树比较 SEO 关键词:Same Tree, 相同的树, 二叉树比较, 同步递归, LeetCode 100 元描述:系统讲透 LeetCode 100 的同步递归与 BFS 成对比较思路,并延伸到配置树、组件树和语法树的等价判断。 目标读者 刚开始刷树题,想建立“成对递归”思维的读者 能写单棵树 DFS,但一涉及“两棵树同时比较”就容易混乱的开发者 需要在配置树、组件树、语法树里判断结构是否一致的工程师 背景 / 动机 很多人第一次做 100,会本能地把问题理解成“分别遍历两棵树,再比较结果”。 这当然能做,但它绕远了。题目真正考的是: 你能不能把 p 和 q 上的对应节点同时拿出来看 你能不能把“相同”的定义拆成一套稳定的判断合同 你能不能在递归里先处理空节点,再处理值和子树 这类思维在后续很多树题里都会反复出现,比如: 判断一棵树是否是另一棵树的子树 判断左右子树是否镜像对称 校验两份树形配置是否结构等价 所以 100 虽然简单,但它是“双树同步递归模板”的起点。 核心概念 同步递归:递归函数参数不是一个节点,而是一对节点 p 和 q 结构相同:对应位置都存在节点,且左右子树结构也一致 值相同:对应位置的节点值相等 成对遍历:无论 DFS 还是 BFS,核心都是“每次处理一对节点” A — Algorithm(题目与算法) 题目还原 给你两棵二叉树的根节点 p 和 q,编写一个函数来检验这两棵树是否相同。 ...
副标题 / 摘要 反转链表 II 的关键不在“会反转”,而在“只反转中间一段且不破坏两端连接”。本文用 ACERS 结构讲清哑节点定位、头插法重排与边界处理,给出可复用模板与多语言代码。 预计阅读时长:12~15 分钟 标签:链表、区间反转、哑节点 SEO 关键词:Reverse Linked List II, 反转链表 II, 区间反转, 哑节点, 头插法, LeetCode 92 元描述:单链表区间反转的工程化模板:哑节点 + 头插法,O(n)/O(1),附推导、常见坑与多语言实现。 目标读者 已会 206 反转链表,想进一步掌握“局部反转”的同学 经常在链表题里卡边界(left=1、right=n)的中级开发者 希望把链表指针操作做成稳定模板的工程师 背景 / 动机 Reverse Linked List(206)是“整条反转”,而 92 要求“只反转一个闭区间”。 这类“局部重排”在工程里非常常见: 任务链中的某个分段要逆序重放 事件日志只对一段做回滚重连 数据结构需要在不重建节点的前提下原地调整 难点并非复杂算法,而是: 找准区间前驱与区间首节点 反转过程中不丢失后续链路 区间反转后把前后两端重新接回去 核心概念 哑节点(dummy):统一处理 left = 1 场景,避免头节点特判地狱 前驱指针 prev:最终停在第 left-1 个节点(若 left=1 则停在 dummy) 当前指针 cur:初始为区间首节点 prev.next 头插法(head insertion):每次把 cur 后面的一个节点摘下,插到 prev 后面 A — Algorithm(题目与算法) 题目还原 给你单链表的头节点 head 和两个整数 left、right(1 <= left <= right <= n), 请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表。 ...
副标题 / 摘要 固定间距 1 检测是典型的“事件间距校验”模型。本文按 ACERS 结构拆解题意、原理与工程迁移,并给出多语言可运行实现。 预计阅读时长:10~12 分钟 标签:数组、双指针、事件间距 SEO 关键词:固定间距 1 检测, 事件间距, LeetCode 1437, O(n) 元描述:一次扫描判断所有 1 是否至少相隔 k 个位置,含工程场景、复杂度对比与多语言代码。 目标读者 刷 LeetCode 并希望沉淀“模板题”的学习者 做监控/风控/行为分析的工程师 需要判断事件间隔是否合规的系统开发者 背景 / 动机 许多系统都有“事件不能过密”的约束:例如登录失败、报警事件、敏感操作、API 调用等。 这类问题的本质是 “事件间距是否满足阈值”,与该题完全等价。 如果能用 O(n) 一次扫描完成校验,就能直接迁移到实时系统。 核心概念 事件间距:两个事件之间至少有 k 个“空位” 在线校验:只记住上一次事件的位置即可 边界处理:初始化 last = -k-1,消除首个事件特判 A — Algorithm(题目与算法) 题目还原 给定整数数组 nums 与整数 k,若任意两个 1 之间至少有 k 个 0(等价于两次 1 的索引差 > k),返回 true,否则返回 false。 输入输出 名称 类型 描述 nums int[] 仅包含 0/1 的数组 k int 需要的最小间隔 返回 bool 是否满足间距约束 示例 1 nums = [1,0,0,0,1,0,0,1], k = 2 输出: true 示例 2 nums = [1,0,1], k = 2 输出: false C — Concepts(核心思想) 关键观察 只需要记住 上一个 1 的索引 last 当遇到新的 1:若 i - last <= k,说明间隔不足 否则更新 last = i 方法归类 单次线性扫描(One-pass Scan) 事件间距校验(Event Spacing Check) 双指针 / 贪心(Greedy with last pointer) 数学表达 若 i 和 j 是两个 1 的索引(i < j),要求: ...
副标题 / 摘要 2 的幂判断是位运算最经典的模板题之一。本文按 ACERS 结构讲清原理、工程场景与常见误区,并给出可复用的多语言实现。 预计阅读时长:8~12 分钟 标签:位运算、二进制、数学 SEO 关键词:Power of Two, 2 的幂, 位运算, bit manipulation, LeetCode 231 元描述:用位运算 O(1) 判断 2 的幂,含工程应用、复杂度分析与多语言代码。 目标读者 刚开始接触位运算的算法学习者 想沉淀“位运算模板题”的中级开发者 在系统/后端中需要对齐、分片、容量判断的工程师 背景 / 动机 “2 的幂”是很多工程系统的隐含约束:哈希表容量、内存对齐、任务分片、FFT 窗口大小等。 如果每次判断都用循环或除法,不仅慢,而且容易写出边界错误。 位运算提供了 O(1) 的稳定判断,是可长期复用的基础能力。 核心概念 二进制表示:2 的幂在二进制中只有一个 1,其余全是 0 位与运算:n & (n - 1) 会清除最低位的 1 必要条件:n > 0,排除 0 和负数 A — Algorithm(题目与算法) 题目还原 给定一个整数 n,判断它是否为 2 的幂。 如果是返回 true,否则返回 false。 输入输出 名称 类型 说明 n int 待判断整数 返回 bool 是否为 2 的幂 示例 1 输入: n = 1 输出: true 解释: 2^0 = 1 示例 2 输入: n = 12 输出: false 解释: 12 的二进制是 1100,含多个 1 C — Concepts(核心思想) 核心原理:一次位运算完成判断 2 的幂的二进制形态:1000...000(只有一个 1) n - 1 会把这个 1 变成 0,右侧全部变成 1 因此: n = 1000...000 n - 1 = 0111...111 n & (n - 1) = 0000...000 结论: ...
副标题 / 摘要 最大元音子串数量是“固定窗口计数”的标准模板题。本文按 ACERS 结构讲清楚滑动窗口的核心思想,并给出工程场景与多语言实现。 预计阅读时长:10~12 分钟 标签:滑动窗口、字符串、固定窗口 SEO 关键词:Maximum Number of Vowels, 最大元音子串, 滑动窗口, 固定窗口 元描述:滑动窗口求固定长度子串最大元音数,含工程化应用与多语言代码。 目标读者 正在刷 LeetCode / Hot100 的同学 想建立“固定窗口计数”模板的中级开发者 需要做日志/指标窗口统计的工程师 背景 / 动机 固定长度窗口内的最大计数是工程里极常见的需求: 监控系统统计异常峰值、运营分析统计活跃峰值、NLP 统计特征峰值。 如果每次窗口都重新计算,会退化为 O(nk)。 滑动窗口能让每步更新变成 O(1),把整体降到 O(n)。 核心概念 固定滑动窗口:窗口长度固定为 k,只右移一位 增量更新:进入右端元素、移除左端元素 条件计数:只统计满足条件(本题为元音)的元素数量 A — Algorithm(题目与算法) 题目重述 给你一个字符串 s 和整数 k。 返回长度为 k 的子串中,元音字符数量的最大值。 输入输出 名称 类型 描述 s string 只包含小写英文字符 k int 窗口长度 返回 int 任意长度为 k 的子串中最大元音数 示例 1 s = "abciiidef", k = 3 输出 = 3 示例 2 s = "aeiou", k = 2 输出 = 2 C — Concepts(核心思想) 方法类型 固定滑动窗口 + 条件计数。 ...