LeetCode热题Top100:核心算法思想与前端实战套路
导航:主要算法思想与代表题目
为了帮助你快速建立知识框架,下表汇总了在LeetCode热题Top100中最为核心的几类算法思想、其关键解题模式以及必须掌握的经典题目。
| 算法思想 | 核心解题套路 | 代表题目 | 前端应用联想 |
|---|---|---|---|
| 双指针与滑动窗口 | 同向/反向指针、窗口收缩条件、哈希表辅助计数 | 三数之和、无重复字符最长子串 | 列表滚动加载、表单输入实时校验 |
| 动态规划 | 定义状态、建立转移方程、确定初始/边界条件、优化空间 | 最大子数组和、爬楼梯、编辑距离 | 虚拟DOM Diff算法中的最小编辑距离 |
| 回溯算法 | 递归树路径选择、状态重置(撤销)、剪枝优化 | 组合总和、全排列、N皇后 | 路由权限树的匹配、可视化配置生成 |
| 数据结构应用 | 哈希表快速查询、堆取极值、栈模拟过程 | 两数之和、合并K个排序链表、有效的括号 | 缓存管理(LRU)、任务调度队列、表达式解析 |
| 数学与位运算 | 利用数学性质、二进制位操作、快速幂 | 多数元素、只出现一次的数字、Pow(x, n) | 权限位标识、颜色编码转换、性能优化计算 |
1. 双指针与滑动窗口
这类算法通过维护一个或多个指针在线性结构上移动,高效解决查找、排序和子序列问题。
1.1 核心思想
其核心是通过指针的移动,以线性的时间复杂度完成遍历,避免嵌套循环。滑动窗口是双指针的一种特殊形式,通过维护一个区间来解决问题。
1.2 解题套路
- 排序:对于无序数组的查找问题(如N数和),通常先排序。
- 指针初始化:根据问题定义指针初始位置(如两端、同起点)。
- 移动逻辑:确定指针移动的条件(如比较和与目标值、判断字符重复)。
- 窗口维护:对于滑动窗口,需明确窗口何时扩大、何时收缩,并用哈希表等结构维护窗口内状态。
1.3 典型题目分析
以 "三数之和" 为例:
- 排序:将数组排序,便于后续去重和指针移动。
- 固定与双指针 :外层循环固定一个数
nums[i],内层用左右指针L和R在i右侧寻找。 - 去重 :当
nums[i]与前一元素相同时跳过,以保证结果不重复。 - 移动逻辑 :计算三数和,若大于0则
R左移,若小于0则L右移,等于0则记录结果并同时移动L和R寻找下一组。
2. 动态规划
动态规划是解决最优化问题 和计数问题的利器,其核心是将复杂问题分解为重叠子问题。
2.1 核心思想
记住过往的结果,避免重复计算。关键在于识别问题是否具有"最优子结构"(大问题的最优解包含小问题的最优解)和"重叠子问题"。
2.2 解题"四部曲"
- 定义状态数组 :明确
dp[i]或dp[i][j]代表什么含义(如:以i结尾的子数组最大和)。 - 建立状态转移方程 :找出
dp[i]与之前状态(如dp[i-1])的关系,这是最难也最关键的一步。 - 确定初始状态和边界条件:给状态数组一个起点。
- 考虑空间优化 :很多时候
dp[i]只依赖于前一个或前几个状态,可以用滚动变量替代完整数组。
2.3 典型题目分析
以 "最大子数组和" 为例:
- 状态定义 :
dp[i]表示以第i个元素结尾的连续子数组的最大和。 - 转移方程 :
dp[i] = max(dp[i-1] + nums[i], nums[i])。含义是:要么将当前数接到前面的子数组后,要么另起炉灶。 - 空间优化 :由于
dp[i]只依赖于dp[i-1],因此可以用一个变量pre来代替整个dp数组,将空间复杂度降至O(1)。
3. 回溯算法
回溯算法是一种通过试错来寻找所有(或部分)解的算法,当探索到某步发现选择不优时,就"回溯"返回。
3.1 核心思想
深度优先搜索 + 状态重置。它沿着树的深度遍历节点,并在返回时撤销(回溯)上一次的选择,尝试其他分支。
3.2 解题套路(回溯模板)
python
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
if 选择不合法: # 剪枝
continue
做选择 # 将选择加入路径
backtrack(路径, 新的选择列表) # 递归
撤销选择 # 从路径中移除该选择
3.3 典型题目分析
以 "组合总和" 为例:
- 递归与路径 :递归函数参数包含当前组合
combination、剩余目标和target、起始索引index(防止重复组合)。 - 结束条件 :当
target减为0时,说明当前路径是一个有效组合,加入结果集。 - 选择与回溯 :从
index开始遍历候选数组,将数加入combination,递归调用(target减去该数),递归返回后从combination末尾移除该数,进行回溯。 - 剪枝 :在遍历前,如果当前候选数已经大于剩余
target,可以直接break循环,提升效率。
4. 数据结构的高级应用
许多题目的高效解法依赖于对基础数据结构(哈希表、堆、栈)的巧妙运用。
4.1 哈希表:快速查找与映射
- 核心用途 :将查找时间从
O(n)降至O(1)。 - 典型场景 :
- 空间换时间:如"两数之和",通过哈希表记录遍历过的值及其索引,快速查找补数。
- 频率统计:如"前 K 个高频元素",先统计频率,再用堆筛选。
4.2 堆(优先队列):动态获取极值
- 核心用途:在动态变化的数据集中,快速获取最大值或最小值。
- 典型场景 :"合并K个升序链表"。
- 初始化:将每个链表的头节点放入最小堆。
- 合并:弹出堆顶(当前最小节点)接入结果链表。
- 动态维护:如果弹出节点有后续节点,将其后续节点加入堆中。这个过程保证了每次都能从K个链表中选出最小的当前节点。
4.3 栈:匹配与消除
- 核心用途:处理具有"最近相关性"的问题。
- 典型场景 :
- 括号匹配:遇到左括号入栈,遇到右括号检查栈顶是否匹配。
- 单调栈:用于解决"下一个更大元素"、"柱状图中最大矩形"等问题,维护栈内元素的单调性。
5. 数学与位运算巧思
部分题目需要发现背后的数学规律,或利用位运算的特性来巧解。
5.1 位运算
- 异或(
^) 的妙用:a ^ a = 0,a ^ 0 = a,且满足交换律。"只出现一次的数字" 利用此性质,将所有数字异或,成对的数字抵消,结果即为只出现一次的数字。 - 与(
&)、或(|)、取反(~):常用于判断奇偶、取特定位、统计1的个数等。
5.2 数学性质
- "多数元素" (出现次数 > n/2):可以使用 Boyer-Moore 投票算法,核心是对抗抵消,最终留下的候选者就是多数元素。
- "Pow(x, n)" :使用 快速幂 算法,将幂次
n转化为二进制,通过平方操作将时间复杂度从O(n)降为O(log n)。
总结与面试建议
面试中考察算法,沟通思路和解决问题的能力比默写代码更重要。
- 先问再写:动手前,先与面试官澄清问题细节、边界条件和输入输出。
- 从暴力法开始:先给出一个最直观的解法(即使时间复杂度高),并分析其瓶颈,这展示了你分析问题的能力。
- 逐步优化:基于暴力法,提出优化思路(例如,"这里可以用哈希表来减少查找时间"),并自然引出更优的算法。
- 复杂度分析:写完代码后,主动分析时间和空间复杂度。
- 关联前端:如果合适,可以简要提一下算法在前端的应用(如表单验证联想滑动窗口),这能体现你的知识迁移和结合实际的能力。