推荐阅读
- 先读高频题型概览与标准模板
- 再按分类刷题并记录可复用思路
- 最后复盘错题,形成个人题库
这里是 Hot100 系列的合集页。每题统一按 ACERS 模板写作,强调“题解模板化 + 工程场景迁移 + 多语言实现”。 推荐阅读 先从数组 / 哈希 / 前缀和等高频主题开始 每题掌握一个可复用的“方法模型” 做完题后再回到工程场景,强化迁移能力
副标题 / 摘要 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(核心思想) 方法类型 固定滑动窗口 + 条件计数。 ...
副标题 / 摘要 这是“连续 1 子串计数”的标准题:用 cur 维护以当前位置结尾的连续 1 长度即可在线累加答案。本文按 ACERS 模板给出清晰模型、工程场景与多语言实现。 预计阅读时长:10~12 分钟 标签:计数、字符串、连续段 SEO 关键词:Number of Substrings With Only 1s, 连续1子串, LeetCode 1513 元描述:在线统计连续 1 子串数量的 O(n) 解法与工程化应用。 目标读者 正在刷 LeetCode / 准备面试的同学 想建立“连续段计数”模板的中级开发者 做日志分析、监控与行为统计的工程师 背景 / 动机 “只含 1 的连续子串数量”看似简单,但它对应一类非常常见的工程统计: 连续事件强度、稳定性评分、连续活跃天数、心跳连续正常等。 掌握这题等于掌握“连续段贡献计数”的可复用模型。 核心概念 连续子串:必须连续,不能跳过元素 连续段(run):一段连续的 1 在线累加(cur 模型):记录以当前位置结尾的连续 1 长度 取模:答案可能很大,需要取 1e9+7 A — Algorithm(题目与算法) 题目重述 给你一个二进制字符串 s,请返回 仅由字符 ‘1’ 组成的子串 的数量。 子串要求连续且非空。 输入输出 名称 类型 描述 s string 只包含 ‘0’ 和 ‘1’ 返回 int 仅含 1 的子串数量(取模) 示例 s = "0110111" 输出 = 9 解释:连续 1 段为长度 2 和 3,贡献分别为 3 和 6,总和 9。 ...
副标题 / 摘要 这是“数据结构基础”系列第 2 题:好数对计数。通过“频次统计 + 组合计数”,把 O(n^2) 直接降到 O(n),并给出可直接迁移到工程的实现方式。 预计阅读时长:8~10 分钟 标签:哈希表、计数、数组 SEO 关键词:Good Pairs, 好数对, hash map, frequency, 计数 元描述:好数对计数的哈希表解法与工程化应用,含复杂度分析与多语言代码。 目标读者 刚开始学习哈希表与计数思想的初学者 希望把刷题方法迁移到业务统计的中级工程师 准备面试,想掌握基础计数模型的同学 背景 / 动机 “找出相同元素的两两组合数量”是一个常见的计数类问题。 在数据去重、行为分析、错误归因等场景里,这类问题通常会被反复遇到。 若用双重循环计算,复杂度是 O(n^2);一旦数据规模扩大就会变慢。 因此需要一个可线性扩展的方案。 A — Algorithm(题目与算法) 题目还原 给你一个整数数组 nums。 如果一组数字 (i, j) 满足 nums[i] == nums[j] 且 i < j,就称为一个 好数对。 返回好数对的数目。 输入输出 名称 类型 描述 nums int[] 整数数组 返回 int 好数对数量 基础示例 nums 输出 说明 [1, 2, 3, 1, 1, 3] 4 (0,3) (0,4) (3,4) (2,5) [1, 1, 1, 1] 6 C(4,2) = 6 [1, 2, 3] 0 无重复 直观图示(示例 1) ...
副标题 / 摘要 一道典型的“乘积 ≥ 阈值”计数题,看起来像是 O(n²) 的双重循环,实际上用「排序 + 二分查找」就能把复杂度压到 O((n+m)log m)。本文从题意抽象、核心公式到多语言实现,带你把这类阈值匹配问题彻底吃透。 预计阅读时长:10~15 分钟 适用场景标签:二分查找、排序计数、阈值匹配 SEO 关键词:spells and potions, successful pairs, 二分查找, lower_bound, 乘积约束 目标读者与背景 目标读者 已熟悉基本二分查找,想提升「在有序数组上做计数」能力的同学 后端 / 算法工程师,经常处理阈值判断与配对统计的问题 准备技术面试,希望积累“排序 + 二分”模板的开发者 为什么这题值得单独写一篇? 它把一个表面 O(n²) 的「所有配对」问题,转化成了对有序数组的二分计数; 公式非常典型:把 a * b ≥ success 转成 b ≥ ceil(success / a); 这种思路在推荐系统、风控额度、资源匹配等业务里屡见不鲜。 A — Algorithm(题目与算法) 题目重述 给定两个整数数组 spells 和 potions,以及一个正整数 success。 对于每个咒语 spells[i],我们定义它与药水 potions[j] 的组合是“成功”的,当且仅当: spells[i] * potions[j] >= success 请返回一个数组 ans,其中 ans[i] 表示第 i 个咒语可以与多少个药水形成成功组合。 ...
副标题 / 摘要 一道看似麻烦的子数组题:长度必须固定为 k,元素种类又要至少 m 个,还要在满足约束下让子数组和最大。本文通过「固定窗口滑动 + 计数哈希表」,构造 O(n) 级别的简洁算法,并给出多语言实现与工程实践案例。 预计阅读时长:12~15 分钟 适用场景标签:滑动窗口进阶、distinct 计数、子数组最大和 SEO 关键词:almost unique subarray, at least m distinct, sliding window, subarray max sum 目标读者与背景 目标读者 已经掌握基础滑动窗口(如「最长无重复子串」)的刷题同学 后端 / 数据分析工程师,需要在数组或数据流上做实时统计 准备中高级面试,希望写出更工程化解法的开发者 问题背景 / 动机 许多业务都有类似需求: 推荐系统:固定长度的推荐位里,既要保证足够多的不同品类,又希望整体评分尽量高; 监控系统:在最近的固定时间窗口里,要求至少有 m 个不同指标处于活跃状态; 行为分析:在 k 次连续行为中,至少访问 m 个不同页面,且总价值最大。 本题正是这类需求的抽象版,非常适合用来练习滑动窗口 + 计数哈希表的组合技。 A — Algorithm(题目与算法) 题目重述 给定整数数组 nums,正整数 m 和 k。 如果一个长度为 k 的子数组中至少包含 m 个不同的元素,则称其为“几乎唯一子数组(almost unique subarray)”。 请在所有几乎唯一子数组中,找到元素和的最大值;如果不存在这样的子数组,则返回 0。 输入 ...