概念
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
模板
// 计算从起点 start 到终点 target 的最近距离
int BFS(Node start, Node target) {
Queue<Node> q; // 核心数据结构
Set<Node> visited; // 避免走回头路
q.offer(start); // 将起点加入队列
visited.add(start);
while (q not empty) {
int sz = q.size();
/* 将当前队列中的所有节点向四周扩散 */
for (int i = 0; i < sz; i++) {
Node cur = q.poll();
/* 划重点:这里判断是否到达终点 */
if (cur is target)
return step;
/* 将 cur 的相邻节点加入队列 */
for (Node x : cur.adj()) {
if (x not in visited) {
q.offer(x);
visited.add(x);
}
}
}
}
// 如果走到这里,说明在图中没有找到目标节点
}
范式题目
题目
力扣https://leetcode.cn/problems/open-the-lock/
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出解锁需要的最小旋转次数,如果无论如何不能解锁,返回 -1 。
示例 1:
输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
输出:6
解释:
可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的,
因为当拨动到 "0102" 时这个锁就会被锁定。
示例 2:输入: deadends = ["8888"], target = "0009"
输出:1
解释:把最后一位反向旋转一次即可 "0000" -> "0009"。
示例 3:输入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
输出:-1
解释:无法旋转到目标数字且不被锁定。
提示:
1 <= deadends.length <= 500
deadends[i].length == 4
target.length == 4
target 不在 deadends 之中
target 和 deadends[i] 仅由若干位数字组成
解题思路
对于每一个在元素队列中的元素,我们要对其每一位进行+1和-1操作,使新生成的每一个数字在判断此前没有加入过队列之后将其加入元素队列,对每一个加入元素队列的数字判断是否在禁止数字队列中,在则continue这个元素,不在则判断这个元素是否为最终结果,不为最终结果则利用这个元素进行+1和 -1的操作,在此过程中利用计数器来计算次数,最终如果cur为找到的元素,返回计数器,否则返回-1(注意的是:我们每次往队列中加入元素都是刚开始只需要判断该元素是否访问过,当cur指向该元素时,再去判断是否在deads中(避免重复判断导致的超时))
实例代码
class Solution {
public int openLock(String[] deadends, String target) {
int res=0;//定义计数器
//定义两个队列
HashSet<String>visited=new HashSet<>();
HashSet<String>deads=new HashSet<>();
LinkedList<String>elements=new LinkedList<>();
//求+1和-1
//加入队列
for(String s:deadends){
deads.add(s);
}
if(deads.contains("0000")){
return -1;
}
elements.offer("0000");
visited.add("00000");
while(elements.size()!=0){
int n=elements.size();
for(int i=0;i<n;++i){
String cur=elements.remove();
if(cur.equals(target)){
return res;
}
//加入观察过的队列
visited.add(cur);
for(int j=0;j<4;++j){
String sub=oneSub(cur,j);
String plus=onePlus(cur,j);
if(!visited.contains(sub)&&!deads.contains(sub)){
//添加元素
elements.offer(sub);
}
if(!visited.contains(plus)&&!deads.contains(plus)){
//添加元素
elements.offer(plus);
}
}
}
res++;
}
return -1;
}
public String onePlus(String cur,int j){
char []chars=cur.toCharArray();
char ch=chars[j];
if(ch=='9'){
chars[j]='0';
}else{
chars[j]+=1;
}
return new String(chars);
}
public String oneSub(String cur,int j){
char []chars=cur.toCharArray();
char ch=chars[j];
if(ch=='0'){
chars[j]='9';
}else{
chars[j]-=1;
}
return new String(chars);
}
}
题目
力扣https://leetcode.cn/problems/minimum-depth-of-binary-tree/
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
示例 2:输入:root = [2,null,3,null,4,null,5,null,6]
输出:5
提示:
树中节点数的范围在 [0, 105] 内
-1000 <= Node.val <= 1000
通过次数574,422提交次数1,099,570
解题思路
利用队列存储树中访问的元素,不断调用对列中的元素,直到某个元素的左右子树全部为空(在过程中使用计数器进行计数,直到叶子结点)
实例代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//定义计数器
int count=0;
//定义数据保存队列
private LinkedList<TreeNode>data=new LinkedList<>();
public int minDepth(TreeNode root) {
if(root==null){
return 0;
}
//将根结点加入队列
data.add(root);
bfs();
return count;
}
public void bfs(){
//while循环遍历深度,for循环遍历同一层
while(data.size()!=0){
count++;
int n=data.size();
for(int i=0;i<n;++i){
TreeNode node=data.remove();
if(node.left==null&&node.right==null){
return;
}
if(node.left!=null){
data.add(node.left);
}
if(node.right!=null){
data.add(node.right);
}
}
}
}
}