1. 实现和特性
定义
搜索-遍历
- 每个节点要访问且仅访问一次
- 对结点的访问顺序
- 深度优先(depth first search)
- 广度优先(breadth first search)
1.1 深度优先搜索
DFS代码(递归写法)及遍历顺序
非递归写法
def DFS(self, tree):
if tree.root is None:
return []
visited, stack = [], [tree.root]
while stack:
node = stack.pop()
visited.add(node)
process (node)
nodes = generate_related_nodes(node)
stack.push(nodes)
# other processing work
...
1.2 广度优先搜索(breadth first search)
使用队列
BFS 使用队列实现
2. 算法题解
1)102. 二叉树的层次遍历
广度优先遍历
- 递归:每层的结点返回到一个数组
- 迭代:维护一个队列,不同层时先将每层结点放入队列,之后遍历队列
并按入队顺序出队并赋给node,将node.val添加到当前数组
递归
// @lc code=start
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
BFS(res, root, 0);
return res;
}
public void BFS(List<List<Integer>> res, TreeNode root, int level) {
if (root == null) return;
// 当层数大于二维数组中的数组数时,上一层的结点已经遍历添加完毕,新建一个数组代表下一层
if (res.size() == level) res.add(new LinkedList());
res.get(level).add(root.val); // 往当前层对应的数组添加结点val
BFS(res, root.left, level + 1);
BFS(res, root.right, level + 1);
}
迭代
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Deque<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<>();
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
res.add(level);
}
return res;
}
}
// @lc code=end
2)433. 最小基因变化
3)[515] 在每个树行中找最大值
广度优先搜索
// @lc code=start
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
BFS(res, root, 0);
return res;
}
public void BFS(List<Integer> res, TreeNode root, int level) {
if (root == null) return;
if (res.size() == level) res.add(level, root.val);
// 每层中每个分支得到的元素比较 进行最大替换
res.set(level, Math.max(res.get(level), root.val));
BFS(res, root.left, level + 1);
BFS(res, root.right, level + 1);
}
}
// @lc code=end
3)岛屿数量
- dfs,遍历二维数组,找单独为1的格子,找到后以1格子为root结点,向下(周围(上下左右))找其他为’1’的格子,没有1结束,继续寻找下一个单独为1的格子,直到二维数组遍历结束
public void DFS(char[] [] grid, int r, int c) {
// 终止条件,当周围某个方向的格子为0时结束此层递归
if (r < 0 || c < 0 || r >= grid.length || c >= grid[0].length || grid[r][c] == '0') return;
grid[r][c] = '0'; // 将访问过为1的格子标记为0
// 深度优先搜索周围(上下左右)的格子
DFS(grid, r - 1, c);
DFS(grid, r + 1, c);
DFS(grid, r, c - 1);
DFS(grid, r, c + 1);
}
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
// 网格高宽
int nr = grid.length;
int nc = grid[0].length;
int num_isLands = 0; // 岛屿数量
// 递归入口,遍历网格出现1时,进入递归,将其周围为1的格子标记为0
for (int r = 0; r < nr; ++r) {
for (int c = 0; c < nc; ++c) {
if (grid[r][c] == '1') {
++num_isLands;
DFS(grid, r, c);
}
}
}
return num_isLands;
}
4)连通块问题BFS
import java.util.*;
import javax.management.Query;
// 设置一个结点存放每次移动的坐标以及步数
class Node {
int x, y, step;
public Node(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
public class Main {
static int n, m;
static char[][] map = new char[1005][1005]; // 存放地图
static Queue<Node> que = new LinkedList<Node>();
// 记录走的四个方向
static int[] dirX = {0, 0, -1, -1, -1, 1, 1, 1};
static int[] dirY = {-1, 1, 1, 0, -1, 1, 0, -1};
// 标记已经走过的坐标
static boolean[][] vis = new boolean[1005][1005];
public static boolean check(int x, int y) {
if (x < 0 || y < 0 || x >= n || y >= m) return false;
if (vis[x][y]) return false;
if (map[x][y] == '.') return false;
return true;
}
public static void bfs(int x, int y) {
Node cur = new Node(x, y, 0);
que.add(cur);
vis[x][y] = true;
while (!que.isEmpty()) {
cur = que.remove();
if (cur.x == n - 1 && cur.y == m - 1) return;
for (int i = 0; i < 8; i++) {
int nextX = cur.x + dirX[i];
int nextY = cur.y + dirY[i];
int nextStep = cur.step + 1;
if (check(nextX, nextY)) {
Node next = new Node(nextX, nextY, nextStep);
que.add(next);
vis[nextX][nextY] = true;
}
}
}
return;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
int cnt = 0;
for(int i = 0; i < n; i++){
String str = sc.next();
map[i] = str.toCharArray();
}
// 当遍历的坐标上是‘W’,执行广度优先搜索,走过的坐标打上标记并cnt++,就可以找到所有独立的水域
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == 'W' && vis[i][j] != true) {
cnt++;
bfs(i, j);
// System.out.println(i+" "+j);
}
}
}
System.out.println(cnt);
}
}
5)二维迷宫BFS
import java.util.*;
import javax.management.Query;
// 设置一个结点存放每次移动的坐标以及步数
class Node {
int x, y, step;
public Node(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
public class Main {
static int n, m;
static char[][] map = new char[1005][1005]; // 存放地图
static Queue<Node> que = new LinkedList<Node>();
// 记录走的四个方向
static int[] dirX = {0, 0, -1, 1};
static int[] dirY = {-1, 1, 0, 0};
// 标记已经走过的坐标
static boolean[][] vis = new boolean[1005][1005];
public static boolean check(int x, int y) {
// 出界
if (x < 0 || y < 0 || x >= n || y >= m) return false;
// 判断是否走过
if (vis[x][y]) return false;
// 判断是否能走
if (map[x][y] == '#') return false;
return true;
}
public static boolean bfs(int x, int y) {
// 创建安Node对象记录初始坐标与步数
Node cur = new Node(x, y, 0);
que.add(cur); // 入队
// 标记当前的位置,表示走过了
vis[x][y] = true;
while (!que.isEmpty()) {
cur = que.remove(); // 出队,并记录
// System.out.println(cur.x + " " + cur.y);
// 当前记录的坐标是地图的终点的话说明走通了
if (cur.x == n - 1 && cur.y == m - 1) return true;
// 遍历要走的四个方向,
for (int i = 0; i < 4; i++) {
int nextX = cur.x + dirX[i];
int nextY = cur.y + dirY[i];
int nextStep = cur.step + 1;
if (check(nextX, nextY)) {
// 判断下一个坐标是否可以走,true的时候就走(入队),并标记这个位置
Node next = new Node(nextX, nextY, nextStep);
que.add(next);
vis[nextX][nextY] = true;
}
}
}
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for(int i = 0; i < n; i++){
String str = sc.next();
map[i] = str.toCharArray();
}
// 广度优先搜索,从起始位置开始, 一步一步走
if (bfs(0, 0)) {
System.out.println("YES");
} else System.out.println("NO");
}
}
6)馋嘴羊BFS
import java.util.*;
class Node {
int x;
int y;
int step;
Node(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
public class Main {
static int n;
static int m;
static int X;
static int Y;
static int[][] map;
static boolean[][] vis;
static int[] dirX = {0, 0, 1, -1};
static int[] dirY = {1, -1, 0, 0};
static Queue<Node> que = new LinkedList<>();
public static boolean check(int x, int y) {
if (x < 0 || y < 0 || x >= n || y >= m) return false;
if (vis[x][y]) return false;
if (map[x][y] == 0) return false;
return true;
}
public static int bfs(int x, int y) {
que.add(new Node(x, y, 0));
vis[x][y] = true;
int re = 1;
while (!que.isEmpty()) {
Node cur = que.remove();
// System.out.println(cur.step);
for (int i = 0; i < 4; i++) {
int nextX = dirX[i] + cur.x;
int nextY = dirY[i] + cur.y;
int nextStep = cur.step++;
if (check(nextX, nextY)) {
re += 1;
Node next = new Node(nextX, nextY, nextStep);
que.add(next);
vis[nextX][nextY] = true;
}
}
}
return re;
}
public static void main(String []args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
X = sc.nextInt();
Y = sc.nextInt();
map = new int [n][m];
vis = new boolean[n][m];
for (int i = 0; i < n; i++) {
String[] str = sc.next().split("");
for (int j = 0; j < m; j++) {
map[i][j] = Integer.parseInt(str[j]);
}
}
System.out.println(bfs(X, Y));
}
}