必须掌握的数据结构及算法
掌握数据结构是应用算法的基础,以下是一些核心结构及其典型应用场景:
-
栈与队列 :栈 用于深度优先搜索、括号匹配;队列用于广度优先搜索、滑动窗口。
-
哈希表 :提供O(1)时间的快速查找,常用于缓存(LRU) 、统计频率、快速判断元素是否存在(如两数之和)。
-
堆(优先队列) :能快速获取最大或最小元素,常用于解决Top K问题 、求中位数等。
-
树 :二叉树 的遍历(前、中、后序)是基础;二叉搜索树 支持高效查找;字典树专门处理字符串前缀问题。
-
并查集 :高效处理分组 、连通性问题(如朋友圈、岛屿数量变种)。
-
前缀和与差分:
-
前缀和:用于快速计算数组某个区间的和。
-
差分:是前缀和的逆运算,用于高效地对数组的某个区间进行批量增减操作
-
下面这个表格整理了最常见的算法思想、核心概念:
|---------------------|-------------------------------------------------|
| 算法分类/思想 | 核心思想/概念 |
| 滑动窗口 | 维护一个可变或固定大小的窗口,在数组/链表/字符串上滑动,高效解决子数组/子串问题。 |
| 双指针 | 使用两个指针协同工作,包括左右指针(用于有序数组的两数之和等)和快慢指针(用于判断链表环等)。 |
| 二分查找 | 在有序搜索空间中,通过比较中间元素快速缩小范围,时间复杂度通常为O(log n)。 |
| 深度/广度优先搜索 (DFS/BFS) | DFS:递归或栈,用于遍历或搜索树/图。 BFS:队列,用于层序遍历或最短路径。 |
| 回溯法 | 一种通过试错寻找所有解的算法,在遇到不可行解时"回溯"至上一步。 |
| 动态规划 (DP) | 将复杂问题分解为重叠子问题,并存储子问题的解以避免重复计算。 |
| 贪心算法 | 每一步都采取当前状态下局部最优的选择,以期望得到全局最优解。 |
| 分治法 | 将问题分解成多个独立的子问题,递归求解后再合并结果。 |
下面以数组 [3,1,4,1,5,9] 为例,展示滑动窗口、双指针、二分查找、DFS/BFS、回溯法、动态规划、贪心算法和分治法的核心思维差异:

各算法详细解析与经典题目
🔍 1. 滑动窗口
-
核心思想 :维护一个窗口(通常由两个指针
left和right界定),在数组或字符串上滑动。通过移动右指针扩大窗口,满足条件后移动左指针收缩窗口,从而在**O(n)**时间内找到满足条件的子区间。 -
关键点 :用于解决连续子数组/子串问题。窗口内的状态(如字符频率、和、最大值)需要高效维护(常用哈希表或单调队列)。
-
经典题目:
-
3. 无重复字符的最长子串:用哈希集合记录窗口内字符,确保无重复。
-
239. 滑动窗口最大值 :使用单调递减队列在O(1)时间内获取窗口最大值。
-
↔️ 2. 双指针
-
核心思想:使用两个指针协同遍历,减少时间复杂度。主要有两种形式:
-
左右指针 :在有序数组两端向中间移动,用于两数之和、反转数组等。
-
快慢指针 :在链表或数组上,以不同速度移动,用于判断循环、找中点、找交点等。
-
-
关键点:通常能将O(n²)的暴力解法优化到O(n)。
-
经典题目:
-
167. 两数之和 II(有序数组):左右指针经典应用。
-
142. 环形链表 II:快慢指针找到环的入口,是数学和编程的巧妙结合。
-
🔎 3. 二分查找
-
核心思想 :在有序的搜索空间中,每次通过比较中间元素,将待搜索区间缩小一半。
-
关键点 :难点在于边界条件 (
while用<还是<=,mid加一还是减一)。有寻找精确值、寻找左边界、寻找右边界三种基本变体。 -
经典题目:
-
34. 在排序数组中查找元素的第一个和最后一个位置:二分查找左右边界的标准模板题。
-
33. 搜索旋转排序数组:二分查找的进阶,需要在局部有序中判断搜索方向。
-
🌳 4. 深度/广度优先搜索
-
核心思想:
-
DFS :深度优先,一条路走到黑,用递归 或栈 实现。常用于遍历所有路径、排列组合、连通性问题。
-
BFS :广度优先,一层层向外扩展,用队列 实现。常用于最短路径、层序遍历。
-
-
关键点 :必须注意避免重复访问 (使用
visited集合或标记已访问元素)。 -
经典题目:
-
200. 岛屿数量:网格DFS/BFS的典范,用"淹没"思想标记访问过的陆地。
-
102. 二叉树的层序遍历:BFS的经典应用。
-
🧩 5. 回溯法
-
核心思想 :一种系统性试错 的算法。它沿决策树前进,当探索到某步发现当前选择不满足条件时,就撤销(回溯) 上一步或几步的选择,尝试其他可能性。
-
关键点 :其核心框架是一个递归函数,包含:选择 -> 递归 -> 撤销选择 。解决全排列、子集、组合、N皇后等需要枚举所有可能解的问题。
-
经典题目:
-
46. 全排列:回溯法最直观的演示,理解"路径"和"选择列表"。
-
78. 子集:求所有子集是另一种经典的回溯场景。
-
🧮 6. 动态规划
-
核心思想 :将复杂问题分解为重叠的子问题 ,并通过保存子问题的解(通常用数组
dp)来避免重复计算,从而高效求解原问题。 -
关键点 :写出正确的 "状态转移方程" 是核心。思考步骤:1) 定义
dp[i]的意义;2) 找出dp[i]如何由dp[0...i-1]推导(状态转移);3) 确定初始值(dp[0]等)。 -
经典题目(按难度进阶):
-
70. 爬楼梯 :入门必做,理解
dp[i] = dp[i-1] + dp[i-2]。 -
53. 最大子数组和 :理解"
dp[i]是以nums[i]结尾的最大和"这一关键定义。 -
300. 最长递增子序列 :经典的一维DP,
dp[i]与之前所有j < i的状态有关。 -
1143. 最长公共子序列:经典的二维DP,理解文本比较的模型。
-
🍬 7. 贪心算法
-
核心思想 :每一步都做出当前看来最优的选择,并希望这样的局部最优能导致全局最优。
-
关键点:难点在于证明贪心策略的正确性。它不像DP考虑所有子问题,因此效率更高,但适用场景更窄。
-
经典题目:
-
455. 分发饼干:经典入门题,用小饼干满足小胃口。
-
122. 买卖股票的最佳时机II:只要今天比昨天贵,就假设昨天买入今天卖出(贪心思想)。
-
➗ 8. 分治法
-
核心思想 :将一个大问题分解成若干个独立的、形式相同的子问题 ,递归求解子问题,最后合并子问题的结果得到原问题的解。
-
关键点 :与DP的关键区别在于,分治法的子问题通常不重叠。归并排序和快速排序是分治法的典型代表。
-
经典题目:
-
215. 数组中的第K个最大元素:通常使用基于快速排序选择算法的分治思想。
-
23. 合并K个升序链表:可以两两合并(分治),优于顺序合并。
-
算法选择指南
- 识别问题特征
| 问题特征 | 优先考虑算法 | 原因 |
|---|---|---|
| 看到:连续子数组/子串 | 滑动窗口 | 天然适合处理连续区间问题 |
| 看到:有序数组查找 | 二分查找 | O(log n) 高效查找 |
| 看到:所有可能解/排列/组合 | 回溯法 | 系统枚举所有可能性 |
| 看到:最优解 + 重叠子问题 | 动态规划 | 避免重复计算,得到最优解 |
| 局部最优 → 全局最优 | 贪心算法 | 高效,但需要证明正确性 |
| 可独立分解的子问题 | 分治法 | 递归分解,适合并行处理 |
| 图/树遍历,最短路径 | BFS/DFS | 适合层级或深 |
-
混合使用策略:
-
DFS + 记忆化 = 记忆化搜索(一种DP实现方式)
-
二分查找 + 贪心 = 解决"最小化最大值"问题
-
BFS + 优先队列 = Dijkstra算法
-