BFS问题及相关应用

广度优先遍历BFS:

广度优先搜索算法(Breadth First Search),又称为"宽度优先搜索"或"横向优先搜索",简称BFS。

它的思想是:从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。需要注意,遍历过的节点不能再次被遍历。

BFS应用:

BFS可用于解决2类问题:

从A出发是否存在到达B的路径;
从A出发到达B的最短路径(这个应该叫最少步骤合理,第一次遍历到目的节点,其所经过的路径为最短路径);注意,使用 BFS 只能求解无权图的最短路径。

实现:

使用队列来存储每一轮遍历得到的节点,对于遍历过的节点,应该将它标记,防止重复遍历。

典例:

计算在网格中从原点到特定点的最短路径长度

[[1,1,0,1],
[1,0,1,0],
[1,1,1,1],
[1,0,1,1]]

  • 1 表示可以经过某个位置,求解从 (0, 0) 位置到 (tr, tc) 位置的最短路径长度。
  • 由于每个点需要保存x坐标,y坐标以及长度,所以必须要用一个类将三个属性封装起来。
  • 由于bfs每次只将距离加一,所以当位置抵达终点时,此时的距离就是最短路径了。
private static class Position {
   int r, c, length;
   public Position(int r, int c, int length) {
       this.r = r;
       this.c = c;
       this.length = length;
   }
}

public static int minPathLength(int[][] grids, int tr, int tc) {
       int[][] next = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
       int m = grids.length, n = grids[0].length;
       Queue<Position> queue = new LinkedList<>();
       queue.add(new Position(0, 0, 1));
       while (!queue.isEmpty()) {
           Position pos = queue.poll();
           for (int i = 0; i < 4; i++) {//4是数组next的长度
               Position nextPos = new Position(pos.r + next[i][0], pos.c + next[i][1], pos.length + 1);
               if (nextPos.r < 0 || nextPos.r >= m || nextPos.c < 0 || nextPos.c >= n) continue;
               if (grids[nextPos.r][nextPos.c] != 1) continue;
               grids[nextPos.r][nextPos.c] = 0;
               if (nextPos.r == tr && nextPos.c == tc) return nextPos.length;
               queue.add(nextPos);
           }
       }
       return -1;
   }

LeetCode相关题解:

279. Perfect Square(Medium)

题目描述:

给定一个正整数n,求和为n的最小全平方数(例如,1,4,9,16,…)。
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.

Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.

解题思路:
  • 思路来源参考@CyC2018Leetcode刷题题解
  • 可以将每个整数看成图中的一个节点,如果两个整数之差为一个平方数,那么这两个整数所在的节点就有一条边。
  • 要求解最小的平方数数量,就是求解从节点 n 到节点 0 的最短路径。
  • 首先生成平方数序列放入数组,然后通过队列,每次减去一个平方数,把剩下的数加入队列,也就是通过bfs的方式,当此时的数刚好等于平方数,则满足题意,由于每次循环level加一,所以最后输出的level就是需要的平方数个数
class Solution {
    public int numSquares(int n) {
        List<Integer> squares = getSquares(n);//获取所有平方数,存在链表中
        Queue<Integer> queue = new LinkedList<>();
        boolean[] marked = new boolean[n + 1];//这里是n+1,比较好计算
        queue.add(n);
        marked[n] = true;
        int level = 0;//level为第几层
        while(!queue.isEmpty()){
            int size = queue.size();         
            level++;
            while(size-- > 0){
                int top = queue.poll();
                for(int s : squares){
                    if (top - s==0){
                        return level;
                    }
                    if (top - s < 0){
                        break;
                    }
                    if (marked[top - s]){
                        continue;
                    }
                    marked[top - s] =true;//标记为true的不再遍历
                    queue.add(top - s);
                }
                
            }
        }
        return n;
    }
    //先定义一个求小于n的所有平方数的方法
    private List getSquares(int n){
        List<Integer> list = new ArrayList<>();
        int square = 1;
        int i = 3;
        while (square <= n){
            list.add(square);
            square += i;
            i += 2;
        }
        return list;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值