面试算法:BFS宽度优先搜索


一、什么是宽度优先搜索?

宽度优先搜索是图的一种遍历策略,它的思想是从一个点开始,辐射状的,一层层的,由近到远遍历 。


二、宽度优先搜索模版

Queue<Node> queue = new LinkedList();
HashMap<Node, Integer> distance = new HashMap<>();
//放入根节点
queue.offer(node);
distance.put(node, 0);//如果不需要记录距离,可以用HashSet

while(!queue.isEmpty()) {
	Node node = queue.poll();
	for (Node neighbor : node.neighbors) {
		if (distance.containsKey(node)) {
			continue;
		}
		distance.put(neighbor, distance.get(neighbor) + 1);
		queue.offer(neighbor);
	}
}

三、三种宽度优先搜索题型

1. 连通块

通过一个点,找到所有图中与之连通的点。

连通块问题都可以用宽度有限搜索模版解决,
但是对于矩阵中的连通块问题,需要用到坐标变换数组,有一个更细化的模版:

Queue<Point> queue = new LinkedList<Point>();
int[] dx = {x1, x2, ..., xn}; // (x + dx[i], y + dy[i]) 为下一个连通点
int[] dy = {y1, y2, ..., yn};
        
queue.offer(new Point(i, j));
while (!queue.isEmpty()) {
	Point head = queue.poll();
	for (int k = 0; k < n; k++) { // 访问下一个连通点
		int newX = head.x + x[k];
		int newY = head.y + y[k];
		if(!inBound(grid, newX, newY)) { //该连通点是不是超出矩阵边界
			continue;
		}
		if (grid[newX][newY] == true) { //是否已经访问过该点
			grid[newX][newY] = false; 
        	queue.offer(new Point(newX, newY));
		}
	}
}

2. 分层遍历

在连通块问题里,我们并不在意宽度有限搜索的层级。但是遇到需要得到宽度优先搜索的层数之类的与层级有关的问题,需要使用分层遍历。
分层遍历的思路是:在宽度优先搜索模版的每个while循环里加多一个循环,把当前层的node都处理掉。把下一层的node都加入queue。这样每次while都处理一层的node。

Queue<Node> queue = new LinkedList();
HashSet<Node> set = new HashSet<>();
//放入根节点
queue.offer(node);
set.add(node);

while(!queue.isEmpty()) {
	int size = queue.size();
	for (int i = 0; i < size; i++) { //多加一个for循环处理所有当前层的node
		Node node = queue.poll();
		for (Node neighbor : node.neighbors) {
			if (set.contains(node)) {
				continue;
			}
			set.add(neighbor);
			queue.offer(neighbor);
	}
	//for 循环结束后,queue里装的是是所有下一层的node
	//这里可以做跟层级相关的操作,比如层数+1,push这层node到array里...
	...
}

3. 拓扑排序

拓扑排序得到一个图中节点的拓扑顺序。如果题目需要用到节点的拓扑顺序,可以考虑使用这个算法。

拓扑排序算法分为三步:

  1. 得到所有node的in-degree
  2. 初始化queue, 放入in-degree为0的点
  3. 宽度优先搜索

模版:

ArrayList<Node> topSort = new ArrayList();

//第一步,得到所有node的in-degree,储存在hashmap里
HashMap<Node, Integer> map = new HashMap();
for (Node node : graph) {
	for (Node neighbor : node.neighbors) {
		if (map.containsKey(neighbor)) {
			map.put(neighbor, map.get(neighbor) + 1);
        } 
        else {
        	map.put(neighbor, 1);
        }
     }
}

//第二步,初始化,把in-degree为0的点放入queue和答案集中  
Queue<Node> queue = new LinkedList();
for (Node node : graph) {
	if (!map.containsKey(node)) { 
		queue.offer(node);
		topSort.add(node);
    }
}

//第三步,宽度优先搜索        
while (!queue.isEmpty()) {
	Node head = queue.poll();
    for (Node neighbor : head.neighbors) {
    	//每遍历到一个node,这个node的in-egree减1
    	map.put(neighbor, map.get(neighbor) - 1); 
        if (map.get(neighbor) == 0) { //in-degree为0的点放入答案集和queue中
        	topSort.add(neighbor);
            queue.offer(neighbor);
        }
	}
}

四、题目

https://blog.csdn.net/Kejonho/article/details/109309787

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值