深度优先搜索和广度优先搜索广泛运用于树和图中,但是它们的应用远远不止如此。
BFS
广度优先搜索一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
第一层:
- 0 -> {6,2,1,5}
第二层:
- 6 -> {4}
- 2 -> {}
- 1 -> {}
- 5 -> {3}
第三层:
- 4 -> {}
- 3 -> {}
每一层遍历的节点都与根节点距离相同。设 di 表示第 i 个节点与根节点的距离,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di <= dj。利用这个结论,可以求解最短路径等 最优解 问题:第一次遍历到目的节点,其所经过的路径为最短路径。应该注意的是,使用 BFS 只能求解无权图的最短路径。
在程序实现 BFS 时需要考虑以下问题:
- 队列:用来存储每一轮遍历得到的节点;
- 标记:对于遍历过的节点,应该将它标记,防止重复遍历。
关于pair类的用法:https://blog.csdn.net/Cainiao111112/article/details/82893017
1. 计算在网格中从原点到特定点的最短路径长度
[[1,1,0,1],
[1,0,1,0],
[1,1,1,1],
[1,0,1,1]]
public static int minPathLength(int[][] grids, int tr, int tc){
if(grids.length < 0 || grids[0] < 0 || tr < 0 || tc < 0)
return -1;
//direction中分别代表右移,左移,上移,下移
final int[][] direction = { {1,0}, {-1,0}, {0,1}, {0,-1} };
//m代表有多少行,n代表多少列
final int m = grids.length, n = girids[0].length;
//queue用来存储接下来要遍历到的点
//Pair存储当前点的坐标
Queue<Pair<Integer, Integer>> queue = new LinkedList<>();
//首先将0,0点入队列
queue.add(new Pair<>(0,0));
//此时没有移动,所以长度为0
int pathLength = 0;
//当队列不为空的时候
while(!queue.isEmpty()){
//size的作用为检测当前queue里面有多少个值,也就代表着走一步可以到达的点有多少个
int size = queue.size();
//每一次循环,pathLength会加一
pathLength++;
//就执行size次循环
while (size-- > 0) {
Pair<Integer, Integer> cur = queue.poll();
for(int[] d : direction){
int nr = cur.getKey() + d[0], nc = cur.getValue() + d[1];
Pair<Integer, Integer> next = new Pair<>(nr, nc);
//判断下一步是否越界
if(next.getKey() < 0 || next.getValue() >= m || next.getKey() >= n
|| next.getValue() < 0)
continue;
//判断当前点的值是否为0,为0代表不可以走
if(grids[next.getKey()][next.getValue] == 0)
continue;
grids[next.getKey()][next.getValue()] =0 //标记
if(next.getKey() == tr && next.getValue() == tc)
return pathLength;
queue.add(next);
}
}
}
return -1;
}
利用二维数组构造一位数组的函数,并且每个点都遍历四个方向, 遍历后的结果如果满足 条件就返回长度,否则 在队列中继续增加下一层的节点。
整个长度是在每一层节点遍历完之后才增加的如图所示,本题目第一层就是0,0; 以此类推,