算法专题 之 广度优先搜索
Posted JAVA万维猿圈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法专题 之 广度优先搜索相关的知识,希望对你有一定的参考价值。
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,利用了广度优先遍历的一种搜索算法,是很多重要的图的算法(Dijkstra单源最短路径算法和Prim最小生成树算法)的原型。下面一起来看看吧:
预计阅读时间:8分钟
广度优先搜索的定义与理解
基本原则:
广度优先搜索类似于树的层次遍历过程,需要借助一个队列来实现,距离最近的节点先被访问,最远的节点最后被访问。具体来说,从某个节点出发,先访问其直接相连的子节点,若子节点不符合,再问其子节点的子节点,按级别顺序依次访问,直到访问到目标节点。
实施步骤:
(1)创建一个visited数组,用来记录已被访问过的顶点;创建一个队列,用来存放每一层的顶点;初始化图G;
(2)从图中的v0开始访问,将visited[v0]数组的值设置为true,同时将v0入队;
(3)只要队列不空,则重复如下操作:
队头顶点u出队
依次检查u的所有邻接顶点w,若visited[w]的值为false,则访问w,并将visited[w]置为true,同时将w入队。
应用场景:
(1)从A出发是否存在到达B的路径;
(2)从A出发到达B的最短路径(这个应该叫最少步骤合理);
(3)二叉树的宽度搜索遍历,从根结点开始沿着树的宽度搜索遍历
深度优先搜索与广度优先搜索:
(1)深度优先搜索算法和广度优先搜索算法在时间复杂度上是一样的;
(2)深度优先更适合目标比较明确,以找到目标为目的的情况;
(3)广度优先更适合在不断扩大遍历范围时找到相对最优解的情况;
实例解析
题目1:对称二叉树
题目描述:给定一个二叉树,检查它是否是镜像对称的。
示例 :
二叉树 [1, 2, 2, 3, 4, 4, 3]是对称的:
1
/ \
2 2
/ \ / \
3 4 4 3
但是这个下面 [1, 2, 2, null, 3, null, 3]则不是镜像对称的:
1
/ \
2 2
\ \
3 3
解题思路:该题有递归和迭代两种方法解决。如果一个树的左子树与右子树镜像对称,那么这个树是对称的,需要满足两个条件,一方面它们的两个根结点具有相同的值;另一方面每个树的右子树都与另一个树的左子树镜像对称。
方法1:递归,时间复杂度为O(n),空间复杂度为O(n)
注:下面代码可左右滑动查看
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return isSymmetric(root.left, root.right);
}
private boolean isSymmetric(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) {
return true;
}
if (t1 == null || t2 == null) {
return false;
}
if (t1.val != t2.val) {
return false;
}
if (isSymmetric(t1.left, t2.right) && isSymmetric(t1.right, t2.left)) {
return true;
}
return false;
}
}
方法2:迭代,找出所有false的情况,剩下的为true,时间复杂度为O(n),空间复杂度为O(n)
注:下面代码可左右滑动查看
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) {
return true;
}
Queue<TreeNode> q1 = new LinkedList();
Queue<TreeNode> q2 = new LinkedList();
q1.offer(root.left);
q2.offer(root.right);
while (!q1.isEmpty() && !q2.isEmpty()){
TreeNode n1 = q1.poll();
TreeNode n2 = q2.poll();
if (n1 == null && n2 == null){
continue;
}
if ((n1 == null && n2 != null) || (n1 != null && n2 == null)) {
return false;
}
if (n1.val != n2.val){
return false;
}
q1.add(n1.left);
q1.add(n1.right);
q2.add(n2.right);
q2.add(n2.left);
}
return true;
}
}
题目1:完全平方数
题目描述:给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 :
输入: n = 12 输出: 3 解释: 12 = 4 + 4 + 4.
输入: n = 13 输出: 2 解释: 13 = 4 + 9.
解题思路:有人看到这道题想到用贪心算法,对于这道题贪心算法是不适用的,例如
12 = 9 + 1 + 1 + 1,由于题目中提到了“完全平方数的个数最少“,凭借这个关键
词“最少“,可以想到类似的最短路径问题,可以用广度优先搜索来实现。
方法1:广度优先遍历
class Solution {
public int numSquares(int n) {
Set<Integer> squareSet = new HashSet<>();
Queue<Integer> queue = new LinkedList<>();
queue.add(n);
int step = 0;
while (!queue.isEmpty()) {
step++;
int size = queue.size();
for (int i = 0; i < size; i++) {
int now = queue.poll();
if (squareSet.contains(now)) {
return step;
}
int max = (int)Math.sqrt(now);
for (int j = max; j > 0; j--) {
int square = j*j;
if (square == now) {
return step;
} else {
if (now == n) {
squareSet.add(square);
}
queue.add(now - square);
}
}
}
}
return -1;
}
}
方法2:动态规划
class Solution {
public int numSquares(int n) {
int[] nums = new int[n+1];
nums[0] = 0;
nums[1] = 1;
for(int i = 2; i <= n; i++){
int tmp = Integer.MAX_VALUE;
for(int j = 1; j*j <= i; j++){
tmp = Math.min(tmp,nums[i-j*j]);
}
nums[i] = tmp+1;
}
return nums[n];
}
}
- END -
以上是关于算法专题 之 广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper)
Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph)
Leetcode之广度优先搜索(BFS)专题-994. 腐烂的橘子(Rotting Oranges)
Leetcode之广度优先搜索(BFS)专题-1162. 地图分析(As Far from Land as Possible)