数组
大家好,我是老马。
今天我们一起来学习一下数组这种数据结构。
主要知识
数组需要拆分下面几个部分:
-
理论介绍
-
源码分析
-
数据结构实现?
-
题目练习(按照算法思想分类)
-
梳理对应的 sdk 包
-
应用实战
因为这个是 leetcode 系列,所以重点是 4、5(对4再一次总结)。
为了照顾没有基础的小伙伴,会简单介绍一下1的基础理论。
简单介绍1,重点为4。其他不是本系列的重点。
算法篇
动态规划-记忆化搜索
递归
二分查找
DFS 深度优先遍历
BFS 广度优先遍历
回溯
贪心
分治:快排、归并
chat
详细介绍一下力扣算法之深度优先遍历
下面是 LeetCode(力扣)中**深度优先遍历(DFS, Depth-First Search)**的详细介绍。
我们从基础定义、模板写法、常见题型,到技巧总结和高频题推荐全面讲解,帮助你吃透 DFS 算法。
🧠 一、什么是深度优先遍历(DFS)?
DFS 是一种优先“往深处探索”,直到无法继续后才“回溯”的搜索策略。
就像走迷宫:你先一直往一个方向走到底,撞墙了再回退换条路。
🧩 二、DFS 的核心特性
特性 | 说明 |
---|---|
递归实现 | DFS 通常使用递归实现,也可以用栈模拟 |
走到黑到底 | 优先沿着某一条路径走到底 |
适合搜索结构 | 图、树、网格、排列组合等结构 |
可配合剪枝、回溯 | 用于构造所有合法解的情况(回溯算法本质就是 DFS) |
🔁 三、DFS 模板写法
✅ 1. 图/网格搜索(二维方向)
void dfs(int[][] grid, int x, int y, boolean[][] visited) {
if (超出边界 || visited[x][y] || grid[x][y] 不合法) return;
visited[x][y] = true;
for (方向 dir : 上下左右) {
dfs(grid, newX, newY, visited);
}
}
✅ 2. 回溯型 DFS(如排列、组合、子集)
void dfs(List<Integer> path, int index) {
if (满足条件) {
res.add(new ArrayList<>(path));
return;
}
for (int i = index; i < n; i++) {
path.add(候选值);
dfs(path, i + 1); // 递归
path.remove(path.size()-1); // 回溯
}
}
🧰 四、DFS 应用场景总结
场景 | 说明 | 高频题目 |
---|---|---|
✅ 二叉树遍历 | DFS 是最自然的遍历方式 | 104. 二叉树最大深度 |
✅ 图遍历 | 判断连通分量、拓扑排序 | 200. 岛屿数量 |
✅ 网格走迷宫 | 搜索路径、区域大小、封闭岛屿 | 130. 被围绕的区域 |
✅ 回溯搜索 | 组合、子集、全排列、N皇后等 | 46. 全排列 |
✅ 构造解空间 | 分割回文串、加减符号、括号匹配 | 131. 分割回文串 |
🌈 五、DFS 与其他算法的关系
算法/结构 | 与 DFS 的关系 |
---|---|
树结构遍历 | DFS 就是前中后序遍历 |
回溯法 | 是一种“构造所有解”的 DFS |
分治 | 通常用 DFS + 合并逻辑 |
动态规划(记忆化) | DFS + 缓存子结果,就是记忆化搜索 |
图算法 | DFS 可用于拓扑排序、环检测、强连通分量等 |
🎯 六、力扣经典 DFS 题型总结
✅ 1. 树型 DFS
题目 | 说明 |
---|---|
104. 二叉树最大深度 | 递归求最大深度 |
226. 翻转二叉树 | 后序递归交换左右 |
112. 路径总和 | 判断是否存在某条路径 |
✅ 2. 网格 DFS
题目 | 说明 |
---|---|
200. 岛屿数量 | 统计连通块数目 |
695. 岛屿的最大面积 | 搜索最大连通面积 |
130. 被围绕的区域 | 边界 DFS 防止被围绕 |
✅ 3. 回溯(DFS + 回退)
题目 | 说明 |
---|---|
46. 全排列 | used 数组标记是否被使用 |
77. 组合 | 递归 + 回溯构造所有组合 |
17. 电话号码的字母组合 | 递归构造所有结果 |
✅ 4. 构造类 DFS
题目 | 说明 |
---|---|
22. 括号生成 | 左右括号平衡构造 |
93. 复原 IP 地址 | 分割 + 剪枝 |
131. 分割回文串 | 子串判回文 + DFS |
🧪 七、DFS 技巧总结
技巧 | 说明 |
---|---|
✅ 剪枝 | 对不可能成功的路径提前 return,提高效率 |
✅ 回溯撤销 | 构造型 DFS 要记得撤销状态(如 path.remove) |
✅ used[] 标记 | 用于排列等避免重复使用 |
✅ visited[][] | 图/网格防止走重复路径 |
✅ 递归返回值 | 有些 DFS 需要返回路径/结果而不是 void |
🚫 八、常见错误
错误类型 | 说明 |
---|---|
无限递归 | 忘记终止条件或 visited 标记 |
回溯出错 | 没有正确撤销 path / 状态 |
参数传错 | dfs(i + 1) 写成了 i++ 等 |
重复结果 | 缺少剪枝 or visited 逻辑不严谨 |
📌 九、DFS 和 BFS 对比
特性 | DFS | BFS |
---|---|---|
搜索顺序 | 一直向下 | 一层层推进 |
实现方式 | 递归或栈 | 队列 |
适合场景 | 构造类、连通性、构造所有解 | 最短路径、层次遍历 |
常用结构 | 树、图、网格 | 图、网格 |
📚 十、DFS 练习路线推荐(递进式)
- 🌱 树类:104, 226, 112
- 🌿 网格:200, 695, 130
- 🌼 回溯:46, 77, 22, 17
- 🌸 构造:93, 131, 241
- 🌺 图类:785, 886(染色)、207(拓扑)
✅ 总结一句话
DFS 是处理「结构复杂」和「解空间大」问题的万能工具,配合回溯、剪枝、记忆化更加强大,是 LeetCode 中必须掌握的核心算法。