博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BFS · 广度优先搜索
阅读量:2430 次
发布时间:2019-05-10

本文共 2960 字,大约阅读时间需要 9 分钟。

为什么有这篇文章

近半年经常刷题,也参加了同学们自行组织的刷题会,到写这篇文章为止 leetcode 已经 AC 了 77 道题目了。时常的总结是必要的,而分享知识不仅能帮助自己树立知识脉络,更能帮助到大家,为学习算法的同学们提供一种参考的思路。

广度优先搜索概要

广度优先搜索(BFS)是在搜索中首先将所处位置的直接邻居访问一遍,再进入下一层重复之前操作的一种搜索。这种算法需要维护一个队列。队列有着先进先出(First In First Out)的性质。算法的开始一般都是把根节点加入到空队列中,然后开始一个结束条件是队列为空的循环。每一次循环中,算法会取得队列最前的一个元素并且访问它的所有邻居。在访问邻居的同时,程序会把邻居添加到队列中。至此广度优先搜索就写完了,程序会按照上述循环把能够访问到的节点都访问一遍。

这种算法可以应用在图,也可以应用在树上。下面我们来看几道跟树这种数据结构有关的题目。

例题 1. N-ary Tree

这道题是典型的广度优先搜索,要求按层遍历树。解答如下:

"""# Definition for a Node.class Node(object):    def __init__(self, val, children):        self.val = val        self.children = children"""class Solution(object):    def levelOrder(self, root):        """        :type root: Node        :rtype: List[List[int]]        """        if root is None:            return []        queue = [(root, 0)]        result = []        while queue:            node, level = queue.pop(0)            while len(result) <= level:                result.append([])            result[level].append(node.val)            for child in node.children:                queue.append((child, level + 1))        return result

我们规定根节点是第 0 层,然后把节点和所在层级放在一个 tuple 里进队。循环的终止条件是队列为空,当队列有元素时,队头出队,我们对元素做一些处理,然后将它的子孙加入队列。在这个问题中,对于元素的操作比较简单,把它加入结果数组中即可。当然,加入之前要保证数组对应的位置有数组存在(结果是一个包含数组的数组),不然会抛出索引越界的异常。

例题 2. 二叉树上的交叉遍历

是一道中等难度的题目,要求交叉遍历二叉树。交叉的意思是从根节点开始,根节点那层从左到右遍历,下一层从右到左,再下一层从左到右,依次循环直到最后一层,期间忽略 null.

# Definition for a binary tree node.# class TreeNode(object):#     def __init__(self, x):#         self.val = x#         self.left = None#         self.right = Noneclass Solution(object):    def zigzagLevelOrder(self, root):        """        :type root: TreeNode        :rtype: List[List[int]]        """        if root is None:            return []        queue = [(root, 0, True)]        result = []        while queue:            node, level, left_to_right = queue.pop(0)            while len(result) <= level:                result.append([])            nodes_on_same_level = [node]            while len(queue) > 0 and queue[0][1] == level:                nodes_on_same_level.append(queue.pop(0)[0])            for n in nodes_on_same_level:                if n.left:                        queue.append((n.left, level + 1, not left_to_right))                if n.right:                    queue.append((n.right, level + 1, not left_to_right))            if left_to_right:                for n in nodes_on_same_level:                    result[level].append(n.val)            else:                for i in range(len(nodes_on_same_level) - 1, -1, -1):                    n = nodes_on_same_level[i]                    result[level].append(n.val)        return result

题目依旧是要求按层遍历,所以广度优先搜索仍然是我选用的方法。于是读者可以发现本题解法和上一题有着很类似的结构,也有人称之为“套公式”。不同的第一处在于队列中的 tuple 现在有三个元素了,增加了末尾的一个布尔类型。该布尔变量值为 True 的时候说明当前层级需要从左往右遍历,反之从右往左。在循环中,程序一次性将一层的节点全部找出,按照布尔变量指定的顺序添加到结果数组中。剩下的工作就是将子节点进队,和上一题同样的是层级要加 1,不同的是要将布尔变量扭转后再存入队列。

总结

这篇较短的博文首先概括了广度优先搜索的思想,然后通过两道难度有递进的题目进一步介绍了这种算法,希望大家在刷题道路上有更多收获;对我的文章、代码有指点的也欢迎评论,我会即时回复。

转载地址:http://hfpmb.baihongyu.com/

你可能感兴趣的文章
以太坊创始人V 神:普通人看见现在,天才看见未来
查看>>
厉害!从电影花瓶到 Wi-Fi 之母,这才是乘风破浪的姐姐!
查看>>
中国开源大爆发进行时,你没掉队吧?
查看>>
用 Python 实现抖音上的“人像动漫化”特效,原来这么简单!
查看>>
一周内咸鱼疯转 2.4W 次,最终被所有大厂封杀!
查看>>
关于鸿蒙 2.0,那些开发者不知道的一切
查看>>
Google 排名第一的语言,引数十万人关注:搞定它,技术大牛都甘拜下风
查看>>
JavaScript 爆红后,微软为何还要开发 TypeScript?
查看>>
软件开发行业,年轻与大龄程序员的生存现状
查看>>
王者荣耀活动精选 Blink 第二弹来袭!
查看>>
打开数“智”化之门,一字之差带来的思考
查看>>
阿里技术人的成长路径是什么?
查看>>
你值得拥有!更省钱地完成数据监听
查看>>
漫画 | TCP,一个悲伤的故事
查看>>
张一鸣无圈胜破圈?
查看>>
抓紧!抓紧!CSDN年终重榜福利来了~人手一份,快来投稿!!
查看>>
干货! AI 推断解决方案栈 Vitis AI 全流程独家解析
查看>>
真相了 | 敲代码时,程序员戴耳机究竟在听什么?
查看>>
回首互联网十年,我们能从八次烧钱大战中学到什么
查看>>
漫画:如何辨别二逼互联网公司!?
查看>>