在上一篇文章中,我使用到了深度优先算法,它是一种处理点线点之间问题的一种思路。
简单的来说,深度优先算法可以简单理解为从一个方向上死磕,如果这个方向上行不通,那就回到最近的一个分叉点,走另一个方向进行尝试解决。其这种深入死磕的方式,被我们称为深度优先算法。
但往往在图解问题上,深度优先算法并不是最优解决的算法方案。这个时候,我们就要考虑使用广度优先算法了。
广度优先算法,顾名思义,它与深度优先算法成两个对立面,它会充分的往每个方向尝试,从而找到最优解。
我们可以看下这道比较简单的题目,作为我们学习广度优先算法的入门算法题
出自力扣的104题,链接如下

可以给大家几分钟思考一下,要破题很简单,但如果使用广度优先算法如何进行解题
我这边直接给大家代码了
简单讲解一下,我将每一层的节点元素放到一个list集合里,通过遍历将它们的子节点们重新生成一个list集合。
通过判断这个集合是否有值来确定深度是否加1,这种解法保证了每一层节点的雨露均沾,一个都不落下。
直到再也没有子节点了,也就能正确确认二叉树的深度了
当然,这道题目也可以用深度优先算法来解决,大家也可以试试看
现在你已经掌握了广度优先算法的精髓,现在来试试这道稍微有点点难度的算法题,它出自力扣算法题第127题,链接如下

在本算法题中,非常抽象的是单词的概念,单词在list集合中,相邻的元素只有一个字母进行改变
那么广度优先算法如何解决这个问题?是不是没有思路与想法
我上面说过,广度优先算法是解决点线点问题的一个解题思路。那么本题只有单词,那不行,我们需要抽象出一个点线点的概念。
从上面相邻元素只有一个字母改变的题目特性来看,这当中的点就是单词里面的字母,这个线连接的就是相邻单词改变的两个字母
有了这个思路,就可以尝试使用广度优先算法来进行解题了,大家也可以试试看
package com.banmoon.arithmetic.leetcode;
import java.util.*;
/**
* <a href="https://leetcode.cn/problems/word-ladder/?envType=problem-list-v2&envId=breadth-first-search">单词接龙</a>
*/
public class Question127 {
public static void main(String[] args) {
Question127 question127 = new Question127();
List<String> wordList = Arrays.asList("hot", "dot", "dog", "lot", "log", "cog");
int i = question127.ladderLength("hit", "cog", wordList);
System.out.println(i);
}
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
// 第 1 步:先将 wordList 放到哈希表里,便于判断某个单词是否在 wordList 里
Set<String> wordSet = new HashSet<>(wordList);
if (wordSet.size() == 0 || !wordSet.contains(endWord)) {
return 0;
}
wordSet.remove(beginWord);
// 第 2 步:图的广度优先遍历,必须使用队列和表示是否访问过的 visited 哈希表
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
Set<String> visited = new HashSet<>();
visited.add(beginWord);
// 第 3 步:开始广度优先遍历,包含起点,因此初始化的时候步数为 1
int step = 1;
while (!queue.isEmpty()) {
int currentSize = queue.size();
for (int i = 0; i < currentSize; i++) {
// 依次遍历当前队列中的单词
String currentWord = queue.poll();
// 如果 currentWord 能够修改 1 个字符与 endWord 相同,则返回 step + 1
if (changeWordEveryOneLetter(currentWord, endWord, queue, visited, wordSet)) {
return step + 1;
}
}
step++;
}
return 0;
}
private boolean changeWordEveryOneLetter(String currentWord, String endWord,
Queue<String> queue, Set<String> visited, Set<String> wordSet) {
char[] charArray = currentWord.toCharArray();
for (int i = 0; i < endWord.length(); i++) {
// 先保存,然后恢复
char originChar = charArray[i];
for (char k = 'a'; k <= 'z'; k++) {
if (k == originChar) {
continue;
}
charArray[i] = k;
String nextWord = String.valueOf(charArray);
if (wordSet.contains(nextWord)) {
if (nextWord.equals(endWord)) {
return true;
}
if (!visited.contains(nextWord)) {
queue.add(nextWord);
// 注意:添加到队列以后,必须马上标记为已经访问
visited.add(nextWord);
}
}
}
// 恢复
charArray[i] = originChar;
}
return false;
}
}
上面代码可以看这段题解,比我讲得更加详细
这道题目虽然难度上升了不少,但核心依旧是图算法的题解,难点在于如何将单词抽象出图的点线点概念。
只要有了这一层概念,就能使用广度优先的思路进行解题了
好了,经过这两道算法题,相信你已经对广度优先算法有了一定的了解,相信遇到类似的问题,也能有对应的思路,剩下的就是具体的代码实现了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。