在处理树结构的问题时,深度优先遍历(DFS) 和 广度优先遍历(BFS) 是两种常见的搜索方式。它们都可以用来查找树中的目标节点,但由于遍历方式不同,在某些场景下效率也会有所区别。
例如:
- 想要找出每一层的最后一个元素时,LeetCode 199 - 二叉树的右视图,使用 BFS 更加直观。
- 若要计算树的最大深度,LeetCode 104 - 二叉树的最大深度,使用 DFS 会更加自然。
Depth-First Search
深度优先遍历会优先深入树的某一条路径到底,再回溯寻找其他路径。它通常使用递归或栈来实现,适合处理“深度”相关的问题,比如最大深度、路径总和、回溯类问题等。
Breadth-First Search
广度优先遍历则是按层级依次向外扩展的方式进行遍历,更符合我们直觉中的“层次遍历”思路。它通常使用**队列(Queue)**来实现。
为什么层次遍历更推荐使用 BFS?
BFS 天生就是一层一层地向外扩展,非常契合“层次遍历”这一场景。当然,DFS 也可以实现层次遍历,但实现逻辑稍微复杂一些。 lc-102
BFS层次遍历
在这里,对于每一层的处理,逻辑就比较清晰
while来处理层,for来处理层内部的数据
var levelOrder = function (root) {
if (!root) return []
let res = []
let queue = [root]
while (queue.length) {
let size = queue.length
let level = []
for (let i = 0; i < size; ++i) {
let node = queue.shift()
level.push(node.val)
if (node.left) queue.push(node.left)
if (node.right) queue.push(node.right)
}
res.push(level)
}
return res
};
DFS层次遍历
在DFS中,来处理层次,这里就需要来判断,当前层与目前的结果数组的大小关系
当当前层 === 结果数组的长度时
说明此时已经探索到了下一层了,而此时res中还没有添加下一层,此时需要push进入一个空数组来存放数据
var levelOrder = function (root) {
if (!root) return []
let res = []
var dfs = function (level, node) {
if (!node) return
// 初始化 n 层的数组,便于 push 元素到 n 层的数组里面
// 第 n 层的时候,res的长度应该为 n
// 例如第 0 层的时候, res里面的长度就为 0
// 第 1 层的时候, [[3]], 此时再push []
// 就成了 [[3], []], 然后就 res[1].push(9)
// [[3], [9]]
if (level === res.length) {
res.push([])
}
res[level].push(node.val)
dfs(level + 1, node.left)
dfs(level + 1, node.right)
}
dfs(0, root)
return res
};