算法专题 之 广度优先搜索

Posted JAVA万维猿圈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法专题 之 广度优先搜索相关的知识,希望对你有一定的参考价值。

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,利用了广度优先遍历的一种搜索算法,是很多重要的图的算法(Dijkstra单源最短路径算法和Prim最小生成树算法)的原型。下面一起来看看吧:

预计阅读时间:8分钟


广度优先搜索的定义与理解

基本原则:

广度优先搜索类似于树的层次遍历过程,需要借助一个队列来实现,距离最近的节点先被访问,最远的节点最后被访问。具体来说,从某个节点出发,先访问其直接相连的子节点,若子节点不符合,再问其子节点的子节点,按级别顺序依次访问,直到访问到目标节点。 


实施步骤:

    (1)创建一个visited数组,用来记录已被访问过的顶点;创建一个队列,用来存放每一层的顶点;初始化图G

    (2)从图中的v0开始访问,将visited[v0]数组的值设置为true,同时将v0入队;

    (3)只要队列不空,则重复如下操作:

  1. 队头顶点u出队

  2. 依次检查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)

算法之广度优先搜索

算法之深度和广度优先搜索算法