7. 深度优先搜索和广度优先搜索

1. 实现和特性

定义
在这里插入图片描述
搜索-遍历

  1. 每个节点要访问且仅访问一次
  2. 对结点的访问顺序
    1. 深度优先(depth first search)
    2. 广度优先(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. 二叉树的层次遍历

广度优先遍历

  1. 递归:每层的结点返回到一个数组
  2. 迭代:维护一个队列,不同层时先将每层结点放入队列,之后遍历队列
    并按入队顺序出队并赋给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)岛屿数量

  1. 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));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值