BFS的基本概念
BFS 是广度优先搜索(Breadth-First Search)的缩写,是一种图遍历算法。它从给定的起始节点开始,逐层遍历图中的节点,直到遍历到目标节点或者遍历完所有可达节点。
BFS 算法的核心思想是先访问当前节点的所有邻居节点,然后再访问邻居节点的邻居节点,依此类推,直到遍历完整个图。
BFS 模版
BFS 使用队列(Queue)数据结构来辅助实现,它按照先进先出(FIFO)的顺序管理待访问的节点。用**集合(Set)**来辅助节点是否已经被访问,算法的基本流程如下:
- 将起始节点放入队列中,并标记为已访问。
- 从队列中取出一个节点,访问该节点,判断该节点是否符合条件。
- 将该节点的所有未访问过的邻居节点加入队列,并标记为已访问。
- 重复步骤 2 和步骤 3,直到队列为空。
模版1:不必记录深度
function BFS(start, target) {
const queue = []; // 核心数据结构
const visited = new Set(); // 避免走回头路
// 将起始节点放入队列中,并标记为已访问。
queue.push(start);
visited.add(start);
while (queue.length > 0) {
const sz = queue.length;
const cur = queue.shift();
/* 划重点:这里判断是否到达终点 */
if (cur === target)
return step;
/* 将 cur 的所有未访问过的邻居节点加入队列,并标记为已访问。 */
for (const x of cur.adj()) {
if (!visited.has(x)) {
queue.push(x);
visited.add(x);
}
}
}
}
模版2:需要记录深度的
function BFS(start, target) {
const queue = []; // 核心数据结构
const visited = new Set(); // 避免走回头路
// 将起始节点放入队列中,并标记为已访问。
queue.push(start);
visited.add(start);
let step = 0; // 记录扩散的步数
while (queue.length > 0) {
const sz = queue.length;
/* 将当前队列中的所有节点向四周扩散 */
for (let i = 0; i < sz; i++) {
const cur = queue.shift();
/* 划重点:这里判断是否到达终点 */
if (cur === target)
return step;
/* 将 cur 的所有未访问过的邻居节点加入队列,并标记为已访问。 */
for (const x of cur.adj()) {
if (!visited.has(x)) {
queue.push(x);
visited.add(x);
}
}
}
/* 划重点:更新步数在这里 */
step++;
}
}
BFS 算法通常用于以下场景:
- 寻找两个节点之间的最短路径。
- 在树或图中寻找特定深度或层级的节点。
- 检查图是否是连通的。
- 拓扑排序。
- 解决迷宫问题等。
例题
111 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
var minDepth = function(root) {
if(root === null){
return 0;
}
// 记录深度
let step = 0;
// BFS关键数据结构
let queue = [];
let visited = new Set();
queue.push(root);
visited.add(root);
while(queue.length > 0){
let size = queue.length;
for(let i = 0;i<size;i++){
/* 划重点:这里判断是否到达终点 */
let node = queue.shift();
if(node.left === null && node.right === null){
return step+1;
}
/* 将 cur 的所有未访问过的邻居节点加入队列,并标记为已访问。 */
if(node.left !== null && !visited.has(node.left)){
queue.push(node.left);
visited.add(node.left);
}
if(node.right !== null && !visited.has(node.right)){
queue.push(node.right);
visited.add(node.right);
}
}
step++;
}
return step;
};
863.二叉树中所有距离为 K 的结点
给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 k 。
返回到目标结点 target 距离为 k 的所有结点的值的列表。 答案可以以 任何顺序 返回。
思路:
需要我们在树中寻找特定深度或层级的节点,但是又不是从根节点开始,因此需要我们将树 转化成 图。
可以通过哈希表和DFS将树转化成图
var distanceK = function(root, target, k) {
// 起点是target,先通过哈希表+DFS将树转化成图
const parents = getParents(root);
// 结果数组
let ans = []
// BFS关键数据结构
let queue = []
const visited = new Set()
queue.push(target);
visited.add(target.val);
// 记录深度
let step = 0;
while(queue.length){
// 遍历每一层的节点
const len = queue.length;
for(let i = 0;i<len;i++){
// 判断当前节点是否符合条件。
const node = queue.shift();
if(step === k){
ans.push(node.val);
}
// 将相邻的节点都放入到
if(node.left && !visited.has(node.left.val)){
queue.push(node.left);
visited.add(node.left.val);
}
if(node.right && !visited.has(node.right.val)){
queue.push(node.right);
visited.add(node.right.val);
}
if(parents.has(node.val) && !visited.has(parents.get(node.val).val)){
queue.push(parents.get(node.val));
visited.add(parents.get(node.val).val);
}
}
// 遍历完一层后深度+1
step++;
}
return ans;
};
function getParents(root) {
const parents = new Map();
const findParents = (root) => {
if (root.left) {
parents.set(root.left.val, root);
findParents(root.left);
}
if (root.right) {
parents.set(root.right.val, root);
findParents(root.right);
}
};
findParents(root);
return parents;
}