[算法整理]BFS
核心概念
BFS一般都是解决:从一个点到一个点的最短距离和层序遍历问题
BFS的核心其实就是处理一个队列queue,不断地压入和弹出数据,进行判断,他是不是距离最近的那个节点
模板
// 判断最小次数
function BFS(start:number,target:number): number {
// BFS基本,首先新建一个队列
const queue: string[] = new Array();
// 设置一个set,表示已访问的点
const visited = new Set()
// 将start加入到queue里面
queue.push(start)
// 设置次数
let count = 0
while (queue.length) {
// BFS需要层层遍历
let size = queue.length;
// 遍历
for (let i = 0; i < size; i++){
let cur= queue.shift()
// 将周边的节点放进去
for (let i = 0; i < cur.length; i++){
if (!visited.has(up)) {
queue.push(up)
visited.add(up)
}
}
}
count++
}
return -1
};
相关题目
二叉树的最小深度
链接:111. 二叉树的最小深度 - 力扣(LeetCode)
解题思路:
- 需要明确这里是哪两个点
start:就是那个root节点target:就是那个距离root节点最近的那个叶子节点
- 关于
BFS最主要的就是维护一个队列,所以首先我们需要将root压入 - 然后取层层的遍历,找出那个叶子节点
- 因为你是按顺序层层遍历的,所以,第一个叶子节点一定就是那个距离最近的叶子节点
- 因为需要返回深度,所以设置
depth
代码:
function minDepth(root: TreeNode | null): number {
// 一般DFS用于处理最小距离问题,我们设定
// target为距离root最近的那个叶子节点
// start为根节点
// DFS要求就是一个队列
// 因为是二叉树的原因,所以不会出现环
// 处理特殊情况
if(root === null){
return 0
}
const queue:TreeNode[] = new Array();
let depth = 1
// 将root放进去
queue.push(root)
while(queue.length){
// 从前往后,层序遍历,所以我们一个一个取
let size = queue.length;
for(let i =0;i<size;i++){
let curNode = queue.shift();
if(curNode.left === null && curNode.right === null){
return depth
}
if(curNode.left!== null){
queue.push(curNode.left)
}
if(curNode.right!== null){
queue.push(curNode.right)
}
}
depth++
}
return depth
};
打开转盘锁
解题思路:
- 其实本题也可以看为是一个
BFSstart:就是那个0000target:就是那个参数
- 其实他会构成一个
图,在不考虑死亡区的情况下,我们每个abcd每次转动以为都有8中可能,但是他们是会有形成环的可能,所以我们就需要设置一个set来表示我访问过的节点 - 因为存在着死亡区,所以我们还要使用
set来进行表示死亡区的数字 - 同样的
BFS,也是维护一个队列,对队列进行unshift和push,依次去判断是不是target,存不存在在死亡区
代码:
// 设置一个plusOne函数
const plusOne = (s: string, j: number):string=>{
// 每次移动一个
let arr:string[] = s.split("")
if (arr[j] === "9") {
arr[j] = "0"
} else {
arr[j] = parseInt(arr[j])+1+''
}
return arr.join("")
}
// 设置一个minusOne
const minusOne = (s: string, j: number): string => {
// 每次减一
// 先变为数组
let arr: string[] = s.split("")
if (arr[j] === "0") {
arr[j] = "9"
} else {
arr[j] = parseInt(arr[j])-1+''
}
return arr.join("")
}
// 判断最小次数
function openLock(deadends: string[], target: string): number {
// BFS基本,首先新建一个队列
const queue: string[] = new Array();
// 因为0000,每个四位数字移动一次,都有八种可能,但是我们需要排除环
// 设置一个set,表示已访问的点
const visited = new Set()
// 因为存在死亡区,所以我们需要设置一个set,后续判断是不是出现了
const dead = new Set()
for (let value of deadends) {
dead.add(value)
}
// 将start加入到queue里面
queue.push("0000")
// 设置次数
let count = 0
while (queue.length) {
// BFS需要层层遍历
let size = queue.length;
// 遍历
for (let i = 0; i < size; i++){
let cur= queue.shift()
if (dead.has(cur)) {
continue;//继续
}
if (target === cur + '') {
return count
}
// 否则的话
// 因为每次转动一个数组字
for (let i = 0; i < 4; i++){
let up = plusOne(cur + "", i);
if (!visited.has(up)) {
queue.push(up)
visited.add(up)
}
let down = minusOne(cur + '', i);
if (!visited.has(down)) {
queue.push(down)
visited.add(down)
}
}
}
count++
}
return -1
};
二叉树的层序遍历
链接:102. 二叉树的层序遍历 - 力扣(LeetCode)
解题思路:
- 这里我们用到的其实也是一个
BFS,那么很明显就是来维护一个队列queue - 按照题目的要求,也就是我们每一层用一个数组来进行表示,也就是在这一层结束以后,我们需要将这一层所表示的数组
push进我的res结果里 - 那么现在就需要解决的问题是,如何表示这一层呢?
- 假如,现在我们处于根节点那一层,那我肯定那一层只有一个根节点
- 那么往下,我的第二层,肯定是由我根节点的左右节点组成的,那么我们就将
左,右节点放进去,并统计len,这个len就是表示:我这一层的节点个数 - 那么我现在只需要将这个节点的值,放进去
list就完了
代码:
function levelOrder(root: TreeNode | null): number[][] {
// 这是一个BFS,主要核心就是维护一个数组,对数组进行pop和push
// 首先先将单个元素push进去
let res:number[][] = []
// 这个就是判断已经走了哪些节点
let queue:TreeNode[] = []
queue.push(root)
if(!root){
return res
}
while(queue.length){
let size = queue.length;
//console.log("size",size)
//console.log("queue",queue)
//获取这一层的节点
let list = []
// 向四处进行扩散
for(let i = 0;i<size;i++){
// 首先向取出队列里的第一个节点
let cur:TreeNode = queue.shift()
//
list.push(cur.val)
//console.log("list",list)
//判断它是不是又左右节点
if(cur.left){
// 那么在队列里插入
queue.push(cur.left)
}
if(cur.right){
queue.push(cur.right)
}
}
// 这时,这一层已经遍历好了
res.push(list)
}
return res
};